ActionComm::fetchResources()   B
last analyzed

Complexity

Conditions 8

Size

Total Lines 36
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 25
nop 0
dl 0
loc 36
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
/* Copyright (C) 2002-2004  Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004-2011  Laurent Destailleur         <[email protected]>
5
 * Copyright (C) 2005-2012  Regis Houssin               <[email protected]>
6
 * Copyright (C) 2011-2017  Juanjo Menent               <[email protected]>
7
 * Copyright (C) 2015	    Marcos García		        <[email protected]>
8
 * Copyright (C) 2018	    Nicolas ZABOURI	            <[email protected]>
9
 * Copyright (C) 2018-2024  Frédéric France             <[email protected]>
10
 * Copyright (C) 2024		MDW						    <[email protected]>
11
 * Copyright (C) 2024		William Mead			    <[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\Comm\Classes;
29
30
use Dolibarr\Code\Categories\Classes\Categorie;
31
use Dolibarr\Code\Contact\Classes\Contact;
32
use Dolibarr\Code\Core\Classes\CMailFile;
33
use Dolibarr\Code\Core\Classes\Form;
34
use Dolibarr\Code\Core\Classes\HookManager;
35
use Dolibarr\Code\Core\Classes\WorkboardResponse;
36
use Dolibarr\Code\Societe\Classes\Societe;
37
use Dolibarr\Code\User\Classes\User;
38
use Dolibarr\Core\Base\CommonObject;
39
use DoliDB;
40
41
/**
42
 *       \file       htdocs/comm/action/class/actioncomm.class.php
43
 *       \ingroup    agenda
44
 *       \brief      File of class to manage agenda events (actions)
45
 */
46
47
/**
48
 *      Class to manage agenda events (actions)
49
 */
50
class ActionComm extends CommonObject
51
{
52
    /**
53
     * @var string ID to identify managed object
54
     */
55
    public $element = 'action';
56
57
    /**
58
     * @var string Name of table without prefix where object is stored
59
     */
60
    public $table_element = 'actioncomm';
61
62
    /**
63
     * @var string Name of id column
64
     */
65
    public $table_rowid = 'id';
66
67
    /**
68
     * @var string Name of icon for actioncomm object. Filename of icon is object_action.png
69
     */
70
    public $picto = 'action';
71
72
    /**
73
     * @var int<0,2> 0=Default
74
     *               1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
75
     *               2=Same than 1 but accept record if fksoc is empty
76
     */
77
    public $restrictiononfksoc = 2;
78
79
    /**
80
     * @var int Id of the event
81
     */
82
    public $id;
83
84
    /**
85
     * @var string Id of the event. Use $id as possible
86
     */
87
    public $ref;
88
89
    /**
90
     * @var int Id into parent table llx_c_actioncomm (used only if option to use type is set)
91
     *          This field is stored info fk_action. It contains the id into table llx_ac_actioncomm.
92
     */
93
    public $type_id;
94
95
    /**
96
     * @var string Calendar of event (Type of type of event). 'system'=Default calendar, 'systemauto'=Auto calendar, 'birthdate', 'holiday', 'module'=Calendar specific to a module
97
     *             This field contains the type into table llx_ac_actioncomm ('system', 'systemauto', ...). It should be named 'type_type'.
98
     */
99
    public $type;
100
101
    /**
102
     * @var string Code into parent table llx_c_actioncomm (used only if option to use type is set). With default setup, should be AC_OTH_AUTO or AC_OTH.
103
     *             This field contains the code into table llx_ac_actioncomm.
104
     */
105
    public $type_code;
106
107
    /**
108
     * @var string Type label
109
     */
110
    public $type_label;
111
112
    /**
113
     * @var string Color into parent table llx_c_actioncomm (used only if option to use type is set)
114
     */
115
    public $type_color;
116
117
    /**
118
     * @var string Picto for type of event (used only if option to use type is set)
119
     */
120
    public $type_picto;
121
122
    /**
123
     * @var string Free code to identify action. Ie: Agenda trigger add here AC_TRIGGERNAME ('AC_COMPANY_CREATE', 'AC_PROPAL_VALIDATE', ...)
124
     *             This field is stored into field 'code' into llx_actioncomm.
125
     */
126
    public $code;
127
128
    /**
129
     * @var string Agenda event label
130
     */
131
    public $label;
132
133
    /**
134
     * @var int Date creation record (datec)
135
     */
136
    public $datec;
137
138
    /**
139
     * @var int Duration (duree)
140
     */
141
    public $duree;
142
143
    /**
144
     * @var int Date modification record (tms)
145
     */
146
    public $datem;
147
148
    /**
149
     * @var User Object user that create action
150
     * @deprecated
151
     * @see $authorid
152
     */
153
    public $author;
154
155
    /**
156
     * @var User Object user that modified action
157
     * @deprecated
158
     * @see $usermodid
159
     */
160
    public $usermod;
161
162
    /**
163
     * @var int Id user that create action
164
     */
165
    public $authorid;
166
167
    /**
168
     * @var int Id user that modified action
169
     */
170
    public $usermodid;
171
172
    /**
173
     * @var int Date action start (datep)
174
     */
175
    public $datep;
176
177
    /**
178
     * @var int Date action end (datef)
179
     */
180
    public $datef;
181
182
    /**
183
     * @var int This is date start action (datep) but modified to not be outside calendar view.
184
     */
185
    public $date_start_in_calendar;
186
187
    /**
188
     * @var int This is date end action (datef) but modified to not be outside calendar view.
189
     */
190
    public $date_end_in_calendar;
191
192
    /**
193
     * @var int Date action end (datep2)
194
     */
195
    public $datep2;
196
197
    /**
198
     * @var int -1=Unknown duration
199
     * @deprecated Use ($datef - $datep)
200
     */
201
    public $durationp = -1;
202
203
    /**
204
     * @var int 1=Event on full day
205
     */
206
    public $fulldayevent = 0;
207
208
    /**
209
     * @var int 1=???
210
     */
211
    public $ponctuel;
212
213
    /**
214
     * @var int<-1,100> Percentage
215
     */
216
    public $percentage;
217
218
    /**
219
     * @var string Location
220
     */
221
    public $location;
222
223
    /**
224
     * @var int Transparency (ical standard). Used to say if people assigned to event are busy or not by event. 0=available, 1=busy, 2=busy (refused events)
225
     */
226
    public $transparency;
227
228
    /**
229
     * @var int     (0 By default)
230
     */
231
    public $priority;
232
233
    /**
234
     * @var array<int,array{id:int,transparency:int<0,1>}>  Array of users
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<int,array{id:int,transparency:int<0,1>}> at position 12 could not be parsed: Expected '}' at position 12, but found 'int'.
Loading history...
235
     */
236
    public $userassigned = array();
237
238
    /**
239
     * @var int     Id of user owner = fk_user_action into table
240
     */
241
    public $userownerid;
242
243
    /**
244
     * @var array<int,array{id:int,mandatory:int<0,1>,answer_status:int,transparency:int<0,1>}> Array of contact ids
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<int,array{id:int,m...transparency:int<0,1>}> at position 12 could not be parsed: Expected '}' at position 12, but found 'int'.
Loading history...
245
     */
246
    public $socpeopleassigned = array();
247
248
    /**
249
     * @var int[] Array of other contact emails (not user, not contact)
250
     */
251
    public $otherassigned = array();
252
253
    /**
254
     * @var array<int,ActionCommReminder>   Array of reminders
255
     */
256
    public $reminders = array();
257
258
    /**
259
     * @var int thirdparty id linked to action
260
     */
261
    public $socid;
262
263
    /**
264
     * @var int socpeople id linked to action
265
     */
266
    public $contact_id;
267
268
269
    /**
270
     * @var ?Societe Company linked to action (optional)
271
     * @deprecated
272
     * @see $socid
273
     */
274
    public $societe;
275
276
    /**
277
     * @var ?Contact Contact linked to action (optional)
278
     * @deprecated
279
     * @see $contact_id
280
     */
281
    public $contact;
282
283
    // Properties for links to other objects
284
    /**
285
     * @var int         Id of linked object
286
     */
287
    public $fk_element; // Id of record
288
289
    /**
290
     * @var int         Id of linked object, alternative for API or other
291
     */
292
    public $elementid;
293
294
    /**
295
     * @var string      Type of record. This if property ->element of object linked to.
296
     */
297
    public $elementtype;
298
299
    /**
300
     * @var int id of calendar
301
     */
302
    public $fk_bookcal_calendar;
303
304
    /**
305
     * @var string Ical name
306
     */
307
    public $icalname;
308
309
    /**
310
     * @var string Ical color  (Hex value for color on 6 nibles)
311
     */
312
    public $icalcolor;
313
314
    /**
315
     * @var string Extraparam
316
     */
317
    public $extraparams;
318
319
    /**
320
     * @var array<int,array{id:int,type:string,actionparam:string,status:int}> Actions
321
     */
322
    public $actions = array();
323
324
    /**
325
     * @var string Email msgid
326
     */
327
    public $email_msgid;
328
329
    /**
330
     * @var string Email from
331
     */
332
    public $email_from;
333
334
    /**
335
     * @var string Email sender
336
     */
337
    public $email_sender;
338
339
    /**
340
     * @var string Email to
341
     */
342
    public $email_to;
343
344
    /**
345
     * @var string Email tocc
346
     */
347
    public $email_tocc;
348
    /**
349
     * @var string Email tobcc
350
     */
351
    public $email_tobcc;
352
353
    /**
354
     * @var string Email subject
355
     */
356
    public $email_subject;
357
358
    /**
359
     * @var string Email errors to
360
     */
361
    public $errors_to;
362
363
    /**
364
     * @var int number of vote for an event
365
     */
366
    public $num_vote;
367
368
    /**
369
     * @var int if event is paid
370
     */
371
    public $event_paid;
372
373
    /**
374
     * @var int status use but Event organisation module
375
     */
376
    public $status;
377
378
    /**
379
     * @var string IP address
380
     */
381
    public $ip;
382
383
    /*
384
     * Properties to manage the recurring events
385
     */
386
    /** @var string A string YYYYMMDDHHMMSS shared by allevent of same series */
387
    public $recurid;
388
    /** @var string Rule of recurring */
389
    public $recurrule;
390
    /** @var string Repeat until this date */
391
    public $recurdateend;
392
393
    /** @var int Duration of phone call when the event is a phone call */
394
    public $calling_duration;
395
396
397
    /**
398
     * Typical value for a event that is in a todo state
399
     */
400
    const EVENT_TODO = 0;
401
402
    /**
403
     * Typical value for a event that is in a progress state
404
     */
405
    const EVENT_IN_PROGRESS = 50;
406
407
    /**
408
     * Typical value for a event that is in a finished state
409
     */
410
    const EVENT_FINISHED = 100;
411
412
413
    public $fields = array();
414
415
    /**
416
     *      Constructor
417
     *
418
     *      @param      DoliDB      $db      Database handler
419
     */
420
    public function __construct(DoliDB $db)
421
    {
422
        $this->db = $db;
423
424
        $this->ismultientitymanaged = 1;
425
    }
426
427
    /**
428
     *    Add an action/event into database.
429
     *    $this->type_id OR $this->type_code must be set.
430
     *
431
     *    @param    User        $user           Object user making action
432
     *    @param    int<0,1>    $notrigger      1 = disable triggers, 0 = enable triggers
433
     *    @return   int                         Id of created event, < 0 if KO
434
     */
435
    public function create(User $user, $notrigger = 0)
436
    {
437
        global $langs, $conf;
438
439
        $error = 0;
440
        $now = dol_now();
441
442
        // Check parameters
443
        if (!isset($this->userownerid) || (string) $this->userownerid === '') { // $this->userownerid may be 0 (anonymous event) or > 0
444
            dol_syslog("You tried to create an event but mandatory property userownerid was empty (you can define it to 0 for anonymous event)", LOG_WARNING);
445
            $this->errors[] = 'ErrorActionCommPropertyUserowneridNotDefined';
446
            return -1;
447
        }
448
449
        // Clean parameters
450
        $this->label = dol_trunc(trim($this->label), 128);
451
        $this->location = (!empty($this->location) ? dol_trunc(trim($this->location), 128) : "");
452
        $this->note_private = dol_htmlcleanlastbr(trim(empty($this->note_private) ? $this->note : $this->note_private));
453
        if (empty($this->percentage)) {
454
            $this->percentage = 0;
455
        }
456
        if (empty($this->priority) || !is_numeric($this->priority)) {
457
            $this->priority = 0;
458
        }
459
        if (empty($this->fulldayevent)) {
460
            $this->fulldayevent = 0;
461
        }
462
        if (empty($this->transparency)) {
463
            $this->transparency = 0;
464
        }
465
        if ($this->percentage > 100) {
466
            $this->percentage = 100;
467
        }
468
        if (empty($this->datep) && $this->datep != '0') {   // We should not insert event in calendar without a start date
469
            $this->datep = $now;
470
        }
471
        if (!empty($this->datep) && !empty($this->datef)) {
472
            $this->durationp = ($this->datef - $this->datep); // deprecated
473
        }
474
        if (!empty($this->datep) && !empty($this->datef) && $this->datep > $this->datef) {
475
            $this->datef = $this->datep;
476
        }
477
        if (!isset($this->fk_project) || $this->fk_project < 0) {
478
            $this->fk_project = 0;
479
        }
480
        // For backward compatibility
481
        if ($this->elementtype == 'facture') {
482
            $this->elementtype = 'invoice';
483
        }
484
        if ($this->elementtype == 'commande') {
485
            $this->elementtype = 'order';
486
        }
487
        if ($this->elementtype == 'contrat') {
488
            $this->elementtype = 'contract';
489
        }
490
        if (empty($this->fk_element) && !empty($this->elementid)) {
491
            $this->fk_element = $this->elementid;
492
        }
493
494
        if (!is_array($this->userassigned) && !empty($this->userassigned)) {    // For backward compatibility when userassigned was an int instead of an array
495
            $tmpid = (int) $this->userassigned;
496
            $this->userassigned = array();
497
            $this->userassigned[$tmpid] = array('id' => $tmpid, 'transparency' => $this->transparency);
498
        }
499
500
        $userownerid = $this->userownerid;
501
502
        // Be sure assigned user is defined as an array of array('id'=>,'mandatory'=>,...).
503
        if (empty($this->userassigned) || count($this->userassigned) == 0 || !is_array($this->userassigned)) {
504
            $this->userassigned = array($userownerid => array('id' => $userownerid, 'transparency' => $this->transparency));
505
        }
506
507
        if (!$this->type_id || !$this->type_code) {
508
            $key = empty($this->type_id) ? $this->type_code : $this->type_id;
509
510
            // Get id from code
511
            $cactioncomm = new CActionComm($this->db);
512
            $result = $cactioncomm->fetch($key);
513
514
            if ($result > 0) {
515
                $this->type_id = $cactioncomm->id;
516
                $this->type_code = $cactioncomm->code;
517
            } elseif ($result == 0) {
518
                $this->error = $langs->trans('ErrorActionCommBadType', $this->type_id, $this->type_code);
519
                return -1;
520
            } else {
521
                $this->error = $cactioncomm->error;
522
                return -1;
523
            }
524
        }
525
        $code = empty($this->code) ? $this->type_code : $this->code;
526
527
        // Check parameters
528
        if (!$this->type_id) {
529
            $this->error = "ErrorWrongParameters";
530
            return -1;
531
        }
532
533
        $this->db->begin();
534
535
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "actioncomm";
536
        $sql .= "(ref,";
537
        $sql .= "datec,";
538
        $sql .= "datep,";
539
        $sql .= "datep2,";
540
        $sql .= "durationp,"; // deprecated
541
        $sql .= "fk_action,";
542
        $sql .= "code,";
543
        $sql .= "ref_ext,";
544
        $sql .= "fk_soc,";
545
        $sql .= "fk_project,";
546
        $sql .= "note,";
547
        $sql .= "fk_contact,";
548
        $sql .= "fk_user_author,";
549
        $sql .= "fk_user_action,";
550
        $sql .= "label,percent,priority,fulldayevent,location,";
551
        $sql .= "transparency,";
552
        $sql .= "fk_element,";
553
        $sql .= "elementtype,";
554
        $sql .= "fk_bookcal_calendar,";
555
        $sql .= "entity,";
556
        $sql .= "extraparams,";
557
        // Fields emails
558
        $sql .= "email_msgid,";
559
        $sql .= "email_from,";
560
        $sql .= "email_sender,";
561
        $sql .= "email_to,";
562
        $sql .= "email_tocc,";
563
        $sql .= "email_tobcc,";
564
        $sql .= "email_subject,";
565
        $sql .= "errors_to,";
566
        $sql .= "recurid,";
567
        $sql .= "recurrule,";
568
        $sql .= "recurdateend,";
569
        $sql .= "num_vote,";
570
        $sql .= "event_paid,";
571
        $sql .= "status,";
572
        $sql .= "ip";
573
        $sql .= ") VALUES (";
574
        $sql .= "'(PROV)', ";
575
        $sql .= "'" . $this->db->idate($now) . "', ";   // date creation
576
        $sql .= "'" . $this->db->idate($this->datep) . "', ";   // date start event
577
        $sql .= (strval($this->datef) != '' ? "'" . $this->db->idate($this->datef) . "'" : "null") . ", ";
578
        $sql .= ((isset($this->durationp) && $this->durationp >= 0 && $this->durationp != '') ? "'" . $this->db->escape($this->durationp) . "'" : "null") . ", "; // deprecated
579
        $sql .= (isset($this->type_id) ? $this->type_id : "null") . ",";
580
        $sql .= ($code ? ("'" . $this->db->escape($code) . "'") : "null") . ", ";
581
        $sql .= (!empty($this->ref_ext) ? "'" . $this->db->escape($this->ref_ext) . "'" : "null") . ", ";
582
        $sql .= ((isset($this->socid) && $this->socid > 0) ? ((int) $this->socid) : "null") . ", ";
583
        $sql .= ((isset($this->fk_project) && $this->fk_project > 0) ? ((int) $this->fk_project) : "null") . ", ";
584
        $sql .= " '" . $this->db->escape($this->note_private) . "', ";
585
        $sql .= ((isset($this->contact_id) && $this->contact_id > 0) ? ((int) $this->contact_id) : "null") . ", "; // deprecated, use ->socpeopleassigned
586
        $sql .= (isset($user->id) && $user->id > 0 ? $user->id : "null") . ", ";
587
        $sql .= ($userownerid > 0 ? $userownerid : "null") . ", ";
588
        $sql .= "'" . $this->db->escape($this->label) . "', ";
589
        $sql .= "'" . $this->db->escape($this->percentage) . "', ";
590
        $sql .= "'" . $this->db->escape($this->priority) . "', ";
591
        $sql .= "'" . $this->db->escape($this->fulldayevent) . "', ";
592
        $sql .= "'" . $this->db->escape($this->location) . "', ";
593
        $sql .= "'" . $this->db->escape($this->transparency) . "', ";
594
        $sql .= (!empty($this->fk_element) ? ((int) $this->fk_element) : "null") . ", ";
595
        $sql .= (!empty($this->elementtype) ? "'" . $this->db->escape($this->elementtype) . "'" : "null") . ", ";
596
        $sql .= (!empty($this->fk_bookcal_calendar) ? "'" . $this->db->escape($this->fk_bookcal_calendar) . "'" : "null") . ", ";
597
        $sql .= ((int) $conf->entity) . ",";
598
        $sql .= (!empty($this->extraparams) ? "'" . $this->db->escape($this->extraparams) . "'" : "null") . ", ";
599
        // Fields emails
600
        $sql .= (!empty($this->email_msgid) ? "'" . $this->db->escape($this->email_msgid) . "'" : "null") . ", ";
601
        $sql .= (!empty($this->email_from) ? "'" . $this->db->escape($this->email_from) . "'" : "null") . ", ";
602
        $sql .= (!empty($this->email_sender) ? "'" . $this->db->escape($this->email_sender) . "'" : "null") . ", ";
603
        $sql .= (!empty($this->email_to) ? "'" . $this->db->escape($this->email_to) . "'" : "null") . ", ";
604
        $sql .= (!empty($this->email_tocc) ? "'" . $this->db->escape($this->email_tocc) . "'" : "null") . ", ";
605
        $sql .= (!empty($this->email_tobcc) ? "'" . $this->db->escape($this->email_tobcc) . "'" : "null") . ", ";
606
        $sql .= (!empty($this->email_subject) ? "'" . $this->db->escape($this->email_subject) . "'" : "null") . ", ";
607
        $sql .= (!empty($this->errors_to) ? "'" . $this->db->escape($this->errors_to) . "'" : "null") . ", ";
608
        $sql .= (!empty($this->recurid) ? "'" . $this->db->escape($this->recurid) . "'" : "null") . ", ";
609
        $sql .= (!empty($this->recurrule) ? "'" . $this->db->escape($this->recurrule) . "'" : "null") . ", ";
610
        $sql .= (!empty($this->recurdateend) ? "'" . $this->db->idate($this->recurdateend) . "'" : "null") . ", ";
611
        $sql .= (!empty($this->num_vote) ? (int) $this->num_vote : "null") . ", ";
612
        $sql .= (!empty($this->event_paid) ? (int) $this->event_paid : 0) . ", ";
613
        $sql .= (!empty($this->status) ? (int) $this->status : "0") . ", ";
614
        $sql .= (!empty($this->ip) ? "'" . $this->db->escape($this->ip) . "'" : "null");
615
        $sql .= ")";
616
617
        dol_syslog(get_only_class($this) . "::add", LOG_DEBUG);
618
        $resql = $this->db->query($sql);
619
        if ($resql) {
620
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "actioncomm", "id");
621
            $this->ref = (string) $this->id;
622
            $sql = "UPDATE " . MAIN_DB_PREFIX . "actioncomm SET ref='" . $this->db->escape($this->ref) . "' WHERE id=" . $this->id;
623
            $resql = $this->db->query($sql);
624
            if (!$resql) {
625
                $error++;
626
                dol_syslog('Error to process ref: ' . $this->db->lasterror(), LOG_ERR);
627
                $this->errors[] = $this->db->lasterror();
628
            }
629
            // Now insert assigned users
630
            if (!$error) {
631
                //dol_syslog(var_export($this->userassigned, true));
632
                $already_inserted = array();
633
                foreach ($this->userassigned as $key => $val) {
634
                    // Common value with new behavior is to have $val = array('id'=>iduser, 'transparency'=>0|1) and $this->userassigned is an array of iduser => $val.
635
                    if (!is_array($val)) {  // For backward compatibility when $val='id'.
636
                        $val = array('id' => $val);
637
                    }
638
639
                    if ($val['id'] > 0) {
640
                        if (!empty($already_inserted[$val['id']])) {
641
                            continue;
642
                        }
643
644
                        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "actioncomm_resources(fk_actioncomm, element_type, fk_element, mandatory, transparency, answer_status)";
645
                        $sql .= " VALUES(" . ((int) $this->id) . ", 'user', " . ((int) $val['id']) . ", " . (empty($val['mandatory']) ? '0' : ((int) $val['mandatory'])) . ", " . (empty($val['transparency']) ? '0' : ((int) $val['transparency'])) . ", " . (empty($val['answer_status']) ? '0' : ((int) $val['answer_status'])) . ")";
646
647
                        $resql = $this->db->query($sql);
648
                        if (!$resql) {
649
                            $error++;
650
                            dol_syslog('Error to process userassigned: ' . $this->db->lasterror(), LOG_ERR);
651
                            $this->errors[] = $this->db->lasterror();
652
                        } else {
653
                            $already_inserted[$val['id']] = true;
654
                        }
655
                        //var_dump($sql);exit;
656
                    }
657
                }
658
            }
659
660
            if (!$error) {
661
                if (!empty($this->socpeopleassigned)) {
662
                    $already_inserted = array();
663
                    foreach ($this->socpeopleassigned as $id => $val) {
664
                        // Common value with new behavior is to have $this->socpeopleassigned an array of idcontact => dummyvalue
665
                        if (!empty($already_inserted[$id])) {
666
                            continue;
667
                        }
668
669
                        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "actioncomm_resources(fk_actioncomm, element_type, fk_element, mandatory, transparency, answer_status)";
670
                        $sql .= " VALUES(" . ((int) $this->id) . ", 'socpeople', " . ((int) $id) . ", 0, 0, 0)";
671
672
                        $resql = $this->db->query($sql);
673
                        if (!$resql) {
674
                            $error++;
675
                            dol_syslog('Error to process socpeopleassigned: ' . $this->db->lasterror(), LOG_ERR);
676
                            $this->errors[] = $this->db->lasterror();
677
                        } else {
678
                            $already_inserted[$id] = true;
679
                        }
680
                    }
681
                }
682
            }
683
684
            if (!$error) {
685
                // Actions on extra fields
686
                $result = $this->insertExtraFields();
687
                if ($result < 0) {
688
                    $error++;
689
                }
690
            }
691
692
            if (!$error && !$notrigger) {
693
                // Call trigger
694
                $result = $this->call_trigger('ACTION_CREATE', $user);
695
                if ($result < 0) {
696
                    $error++;
697
                }
698
                // End call triggers
699
            }
700
701
            if (!$error) {
702
                $this->db->commit();
703
                return $this->id;
704
            } else {
705
                $this->db->rollback();
706
                return -1;
707
            }
708
        } else {
709
            $this->db->rollback();
710
            $this->error = $this->db->lasterror();
711
            return -1;
712
        }
713
    }
714
715
    /**
716
     *  Load an object from its id and create a new one in database
717
     *
718
     *  @param      User            $fuser          Object user making action
719
     *  @param      int             $socid          Id of thirdparty
720
     *  @return     int                             New id of clone
721
     */
722
    public function createFromClone(User $fuser, $socid)
723
    {
724
        global $hookmanager;
725
726
        $error = 0;
727
728
        $this->db->begin();
729
730
        // Load source object
731
        $objFrom = clone $this;
732
733
        // Retrieve all extrafield
734
        // fetch optionals attributes and labels
735
        $this->fetch_optionals();
736
737
        //$this->fetch_userassigned();
738
        $this->fetchResources();
739
740
        $this->id = 0;
741
        $this->recurid = '';
742
        $this->recurrule = '';
743
        $this->recurdateend = '';
744
745
        // Create clone
746
        $this->context['createfromclone'] = 'createfromclone';
747
        $result = $this->create($fuser);
748
        if ($result < 0) {
749
            $error++;
750
        }
751
752
        if (!$error) {
753
            // Hook of thirdparty module
754
            if (is_object($hookmanager)) {
755
                $parameters = array('objFrom' => $objFrom);
756
                $action = '';
757
                $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
758
                if ($reshook < 0) {
759
                    $this->setErrorsFromObject($hookmanager);
760
                    $error++;
761
                }
762
            }
763
764
            // Call trigger
765
            $result = $this->call_trigger('ACTION_CLONE', $fuser);
766
            if ($result < 0) {
767
                $error++;
768
            }
769
            // End call triggers
770
        }
771
772
        unset($this->context['createfromclone']);
773
774
        // End
775
        if (!$error) {
776
            $this->db->commit();
777
            return $this->id;
778
        } else {
779
            $this->db->rollback();
780
            return -1;
781
        }
782
    }
783
784
    /**
785
     *  Load object from database
786
     *
787
     *  @param  int         $id                 Id of action to get
788
     *  @param  string      $ref                Ref of action to get
789
     *  @param  string      $ref_ext            Ref ext to get
790
     *  @param  string      $email_msgid        Email msgid
791
     *  @param  int<0,1>    $loadresources      1=Load also resources
792
     *  @return int<-1,1>                       Return integer <0 if KO, >0 if OK
793
     */
794
    public function fetch($id, $ref = '', $ref_ext = '', $email_msgid = '', $loadresources = 1)
795
    {
796
        global $langs;
797
798
        if (empty($id) && empty($ref) && empty($ref_ext) && empty($email_msgid)) {
799
            dol_syslog(get_only_class($this) . "::fetch Bad parameters", LOG_WARNING);
800
            return -1;
801
        }
802
803
        $sql = "SELECT a.id,";
804
        $sql .= " a.ref as ref,";
805
        $sql .= " a.entity,";
806
        $sql .= " a.ref_ext,";
807
        $sql .= " a.datep,";
808
        $sql .= " a.datep2,";
809
        $sql .= " a.durationp,"; // deprecated
810
        $sql .= " a.datec,";
811
        $sql .= " a.tms as datem,";
812
        $sql .= " a.code, a.label, a.note as note_private,";
813
        $sql .= " a.fk_soc,";
814
        $sql .= " a.fk_project,";
815
        $sql .= " a.fk_user_author, a.fk_user_mod,";
816
        $sql .= " a.fk_user_action,";
817
        $sql .= " a.fk_contact, a.percent as percentage,";
818
        $sql .= " a.fk_element as elementid, a.elementtype,";
819
        $sql .= " a.priority, a.fulldayevent, a.location, a.transparency,";
820
        $sql .= " a.email_msgid, a.email_subject, a.email_from, a.email_sender, a.email_to, a.email_tocc, a.email_tobcc, a.errors_to,";
821
        $sql .= " c.id as type_id, c.type as type_type, c.code as type_code, c.libelle as type_label, c.color as type_color, c.picto as type_picto,";
822
        $sql .= " s.nom as socname,";
823
        $sql .= " u.firstname, u.lastname as lastname,";
824
        $sql .= " num_vote, event_paid, a.status";
825
        $sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm as a ";
826
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_actioncomm as c ON a.fk_action=c.id ";
827
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as u on u.rowid = a.fk_user_author";
828
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s on s.rowid = a.fk_soc";
829
        $sql .= " WHERE ";
830
        if ($ref) {
831
            $sql .= " a.ref = '" . $this->db->escape($ref) . "'";
832
        } elseif ($ref_ext) {
833
            $sql .= " a.ref_ext = '" . $this->db->escape($ref_ext) . "'";
834
        } elseif ($email_msgid) {
835
            $sql .= " a.email_msgid = '" . $this->db->escape($email_msgid) . "'";
836
        } else {
837
            $sql .= " a.id = " . ((int) $id);
838
        }
839
840
        dol_syslog(get_only_class($this) . "::fetch", LOG_DEBUG);
841
        $resql = $this->db->query($sql);
842
        if ($resql) {
843
            $num = $this->db->num_rows($resql);
844
            if ($num) {
845
                $obj = $this->db->fetch_object($resql);
846
847
                $this->id         = $obj->id;
848
                $this->entity = $obj->entity;
849
                $this->ref        = $obj->ref;
850
                $this->ref_ext    = $obj->ref_ext;
851
852
                // Properties of parent table llx_c_actioncomm
853
                $this->type_id    = $obj->type_id;
854
                $this->type_code  = $obj->type_code;
855
                $this->type_color = $obj->type_color;
856
                $this->type_picto = $obj->type_picto;
857
                $this->type       = $obj->type_type;
858
                /*$transcode = $langs->trans("Action".$obj->type_code);
859
                $this->type       = (($transcode != "Action".$obj->type_code) ? $transcode : $obj->type_label); */
860
                $transcode = $langs->trans("Action" . $obj->type_code . 'Short');
861
862
                $this->code = $obj->code;
863
                $this->label = $obj->label;
864
                $this->datep = $this->db->jdate($obj->datep);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($obj->datep) can also be of type string. However, the property $datep 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...
865
                $this->datef = $this->db->jdate($obj->datep2);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($obj->datep2) can also be of type string. However, the property $datef 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...
866
867
                $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...
868
                $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...
869
870
                $this->note = $obj->note_private; // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$note has been deprecated: Use $note_private instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

870
                /** @scrutinizer ignore-deprecated */ $this->note = $obj->note_private; // deprecated

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
871
                $this->note_private = $obj->note_private;
872
                $this->percentage = $obj->percentage;
873
874
                $this->authorid = $obj->fk_user_author;
875
                $this->usermodid = $obj->fk_user_mod;
876
877
                if (!is_object($this->author)) {
878
                    $this->author = new User($this->db); // To avoid warning
879
                }
880
                $this->author->id = $obj->fk_user_author; // deprecated
881
                $this->author->firstname = $obj->firstname; // deprecated
882
                $this->author->lastname = $obj->lastname; // deprecated
883
                if (!is_object($this->usermod)) {
884
                    $this->usermod = new User($this->db); // To avoid warning
885
                }
886
                $this->usermod->id = $obj->fk_user_mod; // deprecated
887
888
                $this->userownerid = $obj->fk_user_action;
889
                $this->priority             = $obj->priority;
890
                $this->fulldayevent         = $obj->fulldayevent;
891
                $this->location             = $obj->location;
892
                $this->transparency         = $obj->transparency;
893
894
                $this->socid = $obj->fk_soc; // To have fetch_thirdparty method working
895
                $this->contact_id = $obj->fk_contact; // To have fetch_contact method working
896
                $this->fk_project = $obj->fk_project; // To have fetch_projet method working
897
898
                //$this->societe->id            = $obj->fk_soc;         // deprecated
899
                //$this->contact->id            = $obj->fk_contact;     // deprecated
900
901
                $this->fk_element = $obj->elementid;
902
                $this->elementid = $obj->elementid;
903
                $this->elementtype = $obj->elementtype;
904
905
                $this->num_vote = $obj->num_vote;
906
                $this->event_paid = $obj->event_paid;
907
                $this->status = $obj->status;
908
909
                //email information
910
                $this->email_msgid = $obj->email_msgid;
911
                $this->email_from = $obj->email_from;
912
                $this->email_sender = $obj->email_sender;
913
                $this->email_to = $obj->email_to;
914
                $this->email_tocc = $obj->email_tocc;
915
                $this->email_tobcc = $obj->email_tobcc;
916
                $this->email_subject = $obj->email_subject;
917
                $this->errors_to = $obj->errors_to;
918
919
                $this->fetch_optionals();
920
921
                if ($loadresources) {
922
                    $this->fetchResources();
923
                }
924
            }
925
926
            $this->db->free($resql);
927
        } else {
928
            $this->error = $this->db->lasterror();
929
            return -1;
930
        }
931
932
        return $num;
933
    }
934
935
    /**
936
     *    Initialize $this->userassigned & this->socpeopleassigned array with list of id of user and contact assigned to event
937
     *
938
     *    @return   int<-1,1>           Return integer <0 if KO, >0 if OK
939
     */
940
    public function fetchResources()
941
    {
942
        $this->userassigned = array();
943
        $this->socpeopleassigned = array();
944
945
        $sql = 'SELECT fk_actioncomm, element_type, fk_element, answer_status, mandatory, transparency';
946
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'actioncomm_resources';
947
        $sql .= ' WHERE fk_actioncomm = ' . ((int) $this->id);
948
        $sql .= " AND element_type IN ('user', 'socpeople')";
949
        $resql = $this->db->query($sql);
950
        if ($resql) {
951
            // If owner is known, we must but id first into list
952
            if ($this->userownerid > 0) {
953
                $this->userassigned[$this->userownerid] = array('id' => $this->userownerid); // Set first so will be first into list.
954
            }
955
956
            while ($obj = $this->db->fetch_object($resql)) {
957
                if ($obj->fk_element > 0) {
958
                    switch ($obj->element_type) {
959
                        case 'user':
960
                            $this->userassigned[$obj->fk_element] = array('id' => $obj->fk_element, 'mandatory' => $obj->mandatory, 'answer_status' => $obj->answer_status, 'transparency' => $obj->transparency);
961
                            if (empty($this->userownerid)) {
962
                                $this->userownerid = $obj->fk_element; // If not defined (should not happened, we fix this)
963
                            }
964
                            break;
965
                        case 'socpeople':
966
                            $this->socpeopleassigned[$obj->fk_element] = array('id' => $obj->fk_element, 'mandatory' => $obj->mandatory, 'answer_status' => $obj->answer_status, 'transparency' => $obj->transparency);
967
                            break;
968
                    }
969
                }
970
            }
971
972
            return 1;
973
        } else {
974
            dol_print_error($this->db);
975
            return -1;
976
        }
977
    }
978
979
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
980
    /**
981
     *    Initialize this->userassigned array with list of id of user assigned to event
982
     *
983
     *    @param    bool    $override   Override $this->userownerid when empty. TODO This should be false by default. True is here to fix corrupted data.
984
     *    @return   int<-1,1>           Return integer <0 if KO, >0 if OK
985
     */
986
    public function fetch_userassigned($override = true)
987
    {
988
		// phpcs:enable
989
        $sql = "SELECT fk_actioncomm, element_type, fk_element, answer_status, mandatory, transparency";
990
        $sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm_resources";
991
        $sql .= " WHERE element_type = 'user' AND fk_actioncomm = " . ((int) $this->id);
992
993
        $resql2 = $this->db->query($sql);
994
        if ($resql2) {
995
            $this->userassigned = array();
996
997
            // If owner is known, we must but id first into list
998
            if ($this->userownerid > 0) {
999
                // Set first so will be first into list.
1000
                $this->userassigned[$this->userownerid] = array('id' => $this->userownerid);
1001
            }
1002
1003
            while ($obj = $this->db->fetch_object($resql2)) {
1004
                if ($obj->fk_element > 0) {
1005
                    $this->userassigned[$obj->fk_element] = array('id' => $obj->fk_element,
1006
                                                                  'mandatory' => $obj->mandatory,
1007
                                                                  'answer_status' => $obj->answer_status,
1008
                                                                  'transparency' => $obj->transparency);
1009
                }
1010
1011
                if ($override === true) {
1012
                    // If not defined (should not happened, we fix this)
1013
                    if (empty($this->userownerid)) {
1014
                        $this->userownerid = $obj->fk_element;
1015
                    }
1016
                }
1017
            }
1018
1019
            return 1;
1020
        } else {
1021
            dol_print_error($this->db);
1022
            return -1;
1023
        }
1024
    }
1025
1026
    /**
1027
     *    Delete event from database
1028
     *
1029
     *    @param    User        $user           User making the delete
1030
     *    @param    int<0,1>    $notrigger      1 = disable triggers, 0 = enable triggers
1031
     *    @return   int<-2,1>                   Return integer <0 if KO, >0 if OK
1032
     */
1033
    public function delete($user, $notrigger = 0)
1034
    {
1035
        $error = 0;
1036
1037
        dol_syslog(get_only_class($this) . "::delete", LOG_DEBUG);
1038
1039
        $this->db->begin();
1040
1041
        // remove categorie association
1042
        if (!$error) {
1043
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "categorie_actioncomm";
1044
            $sql .= " WHERE fk_actioncomm=" . ((int) $this->id);
1045
1046
            $res = $this->db->query($sql);
1047
            if (!$res) {
1048
                $this->error = $this->db->lasterror();
1049
                $error++;
1050
            }
1051
        }
1052
1053
        // remove actioncomm_resources
1054
        if (!$error) {
1055
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "actioncomm_resources";
1056
            $sql .= " WHERE fk_actioncomm=" . ((int) $this->id);
1057
1058
            $res = $this->db->query($sql);
1059
            if (!$res) {
1060
                $this->error = $this->db->lasterror();
1061
                $error++;
1062
            }
1063
        }
1064
1065
        if (!$error) {
1066
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "actioncomm_reminder";
1067
            $sql .= " WHERE fk_actioncomm = " . ((int) $this->id);
1068
1069
            $res = $this->db->query($sql);
1070
            if (!$res) {
1071
                $this->error = $this->db->lasterror();
1072
                $error++;
1073
            }
1074
        }
1075
1076
        // Removed extrafields
1077
        if (!$error) {
1078
            $result = $this->deleteExtraFields();
1079
            if ($result < 0) {
1080
                $error++;
1081
                dol_syslog(get_only_class($this) . "::delete error -3 " . $this->error, LOG_ERR);
1082
            }
1083
        }
1084
1085
        // remove actioncomm
1086
        if (!$error) {
1087
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "actioncomm";
1088
            $sql .= " WHERE id=" . ((int) $this->id);
1089
1090
            $res = $this->db->query($sql);
1091
            if (!$res) {
1092
                $this->error = $this->db->lasterror();
1093
                $error++;
1094
            }
1095
        }
1096
1097
        if (!$error) {
1098
            if (!$notrigger) {
1099
                // Call trigger
1100
                $result = $this->call_trigger('ACTION_DELETE', $user);
1101
                if ($result < 0) {
1102
                    $error++;
1103
                }
1104
                // End call triggers
1105
            }
1106
1107
            if (!$error) {
1108
                $this->db->commit();
1109
                return 1;
1110
            } else {
1111
                $this->db->rollback();
1112
                return -2;
1113
            }
1114
        } else {
1115
            $this->db->rollback();
1116
            $this->error = $this->db->lasterror();
1117
            return -1;
1118
        }
1119
    }
1120
1121
    /**
1122
     *    Update action into database
1123
     *    If percentage = 100, on met a jour date 100%
1124
     *
1125
     *    @param    User        $user           Object user making change
1126
     *    @param    int<0,1>    $notrigger      1 = disable triggers, 0 = enable triggers
1127
     *    @return   int<-2,1>                   Return integer <0 if KO, >0 if OK
1128
     */
1129
    public function update(User $user, $notrigger = 0)
1130
    {
1131
        $error = 0;
1132
1133
        // Clean parameters
1134
        $this->label = trim($this->label);
1135
        $this->note_private = dol_htmlcleanlastbr(trim(!isset($this->note_private) ? $this->note : $this->note_private));
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$note has been deprecated: Use $note_private instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1135
        $this->note_private = dol_htmlcleanlastbr(trim(!isset($this->note_private) ? /** @scrutinizer ignore-deprecated */ $this->note : $this->note_private));

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1136
        if (empty($this->percentage)) {
1137
            $this->percentage = 0;
1138
        }
1139
        if (empty($this->priority) || !is_numeric($this->priority)) {
1140
            $this->priority = 0;
1141
        }
1142
        if (empty($this->transparency)) {
1143
            $this->transparency = 0;
1144
        }
1145
        if (empty($this->fulldayevent)) {
1146
            $this->fulldayevent = 0;
1147
        }
1148
        if ($this->percentage > 100) {
1149
            $this->percentage = 100;
1150
        }
1151
        //if ($this->percentage == 100 && ! $this->dateend) $this->dateend = $this->date;
1152
        if ($this->datep && $this->datef) {
1153
            $this->durationp = ($this->datef - $this->datep); // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Comm\Classes\ActionComm::$durationp has been deprecated: Use ($datef - $datep) ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1153
            /** @scrutinizer ignore-deprecated */ $this->durationp = ($this->datef - $this->datep); // deprecated

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1154
        }
1155
        //if ($this->date  && $this->dateend) $this->durationa=($this->dateend - $this->date);
1156
        if ($this->datep && $this->datef && $this->datep > $this->datef) {
1157
            $this->datef = $this->datep;
1158
        }
1159
        //if ($this->date  && $this->dateend && $this->date > $this->dateend) $this->dateend=$this->date;
1160
        if ($this->fk_project < 0) {
1161
            $this->fk_project = 0;
1162
        }
1163
1164
        $socid = (($this->socid > 0) ? $this->socid : 0);
1165
        $contactid = (($this->contact_id > 0) ? $this->contact_id : 0);
1166
        $userownerid = ($this->userownerid ? $this->userownerid : 0);
1167
1168
        // If a type_id is set, we must also have the type_code set
1169
        if ($this->type_id > 0) {
1170
            if (empty($this->type_code)) {
1171
                $cactioncomm = new CActionComm($this->db);
1172
                $result = $cactioncomm->fetch($this->type_id);
1173
                if ($result >= 0 && !empty($cactioncomm->code)) {
1174
                    $this->type_code = $cactioncomm->code;
1175
                }
1176
            }
1177
        }
1178
1179
        $code = $this->code;
1180
        if (empty($code) || (!empty($this->oldcopy) && $this->oldcopy->type_code != $this->type_code)) {    // If code unknown or if we change the type, we reset $code too
0 ignored issues
show
Bug Best Practice introduced by
The property type_code does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
1181
            $code = $this->type_code;
1182
        }
1183
1184
        $this->db->begin();
1185
1186
        $sql = "UPDATE " . MAIN_DB_PREFIX . "actioncomm";
1187
        $sql .= " SET percent = '" . $this->db->escape($this->percentage) . "'";
1188
        $sql .= ", fk_action = " . (int) $this->type_id;
1189
        $sql .= ", code = " . ($code ? "'" . $this->db->escape($code) . "'" : "null");
1190
        $sql .= ", label = " . ($this->label ? "'" . $this->db->escape($this->label) . "'" : "null");
1191
        $sql .= ", datep = " . (strval($this->datep) != '' ? "'" . $this->db->idate($this->datep) . "'" : 'null');
1192
        $sql .= ", datep2 = " . (strval($this->datef) != '' ? "'" . $this->db->idate($this->datef) . "'" : 'null');
1193
        $sql .= ", durationp = " . (isset($this->durationp) && $this->durationp >= 0 && $this->durationp != '' ? "'" . $this->db->escape($this->durationp) . "'" : "null"); // deprecated
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Comm\Classes\ActionComm::$durationp has been deprecated: Use ($datef - $datep) ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1193
        $sql .= ", durationp = " . (isset(/** @scrutinizer ignore-deprecated */ $this->durationp) && $this->durationp >= 0 && $this->durationp != '' ? "'" . $this->db->escape($this->durationp) . "'" : "null"); // deprecated

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1194
        $sql .= ", note = '" . $this->db->escape($this->note_private) . "'";
1195
        $sql .= ", fk_project =" . ($this->fk_project > 0 ? ((int) $this->fk_project) : "null");
1196
        $sql .= ", fk_soc =" . ($socid > 0 ? ((int) $socid) : "null");
1197
        $sql .= ", fk_contact =" . ($contactid > 0 ? ((int) $contactid) : "null");
1198
        $sql .= ", priority = '" . $this->db->escape($this->priority) . "'";
1199
        $sql .= ", fulldayevent = '" . $this->db->escape($this->fulldayevent) . "'";
1200
        $sql .= ", location = " . ($this->location ? "'" . $this->db->escape($this->location) . "'" : "null");
1201
        $sql .= ", transparency = '" . $this->db->escape($this->transparency) . "'";
1202
        $sql .= ", fk_user_mod = " . ((int) $user->id);
1203
        $sql .= ", fk_user_action = " . ($userownerid > 0 ? ((int) $userownerid) : "null");
1204
        if (!empty($this->fk_element)) {
1205
            $sql .= ", fk_element=" . ($this->fk_element ? ((int) $this->fk_element) : "null");
1206
        }
1207
        if (!empty($this->elementtype)) {
1208
            $sql .= ", elementtype=" . ($this->elementtype ? "'" . $this->db->escape($this->elementtype) . "'" : "null");
1209
        }
1210
        if (!empty($this->num_vote)) {
1211
            $sql .= ", num_vote=" . ($this->num_vote ? (int) $this->num_vote : null);
1212
        }
1213
        if (!empty($this->event_paid)) {
1214
            $sql .= ", event_paid=" . ($this->event_paid ? (int) $this->event_paid : 0);
1215
        }
1216
        if (!empty($this->status)) {
1217
            $sql .= ", status=" . ($this->status ? (int) $this->status : 0);
1218
        }
1219
        $sql .= " WHERE id=" . ((int) $this->id);
1220
1221
        dol_syslog(get_only_class($this) . "::update", LOG_DEBUG);
1222
        if ($this->db->query($sql)) {
1223
            $action = 'update';
1224
1225
            // Actions on extra fields
1226
            if (!$error) {
1227
                $result = $this->insertExtraFields();
1228
                if ($result < 0) {
1229
                    $error++;
1230
                }
1231
            }
1232
1233
            // Now insert assignedusers
1234
            if (!$error) {
1235
                $sql = "DELETE FROM " . MAIN_DB_PREFIX . "actioncomm_resources where fk_actioncomm = " . ((int) $this->id) . " AND element_type = 'user'";
1236
                $resql = $this->db->query($sql);
1237
1238
                $already_inserted = array();
1239
                foreach ($this->userassigned as $key => $val) {
1240
                    if (!is_array($val)) {  // For backward compatibility when val=id
1241
                        $val = array('id' => $val);
1242
                    }
1243
                    if (!empty($already_inserted[$val['id']])) {
1244
                        continue;
1245
                    }
1246
1247
                    $sql = "INSERT INTO " . MAIN_DB_PREFIX . "actioncomm_resources(fk_actioncomm, element_type, fk_element, mandatory, transparency, answer_status)";
1248
                    $sql .= " VALUES(" . ((int) $this->id) . ", 'user', " . ((int) $val['id']) . ", " . (empty($val['mandatory']) ? '0' : ((int) $val['mandatory'])) . ", " . (empty($val['transparency']) ? '0' : ((int) $val['transparency'])) . ", " . (empty($val['answer_status']) ? '0' : ((int) $val['answer_status'])) . ")";
1249
1250
                    $resql = $this->db->query($sql);
1251
                    if (!$resql) {
1252
                        $error++;
1253
                        $this->errors[] = $this->db->lasterror();
1254
                    } else {
1255
                        $already_inserted[$val['id']] = true;
1256
                    }
1257
                    //var_dump($sql);exit;
1258
                }
1259
            }
1260
1261
            if (!$error) {
1262
                $sql = "DELETE FROM " . MAIN_DB_PREFIX . "actioncomm_resources where fk_actioncomm = " . ((int) $this->id) . " AND element_type = 'socpeople'";
1263
                $resql = $this->db->query($sql);
1264
1265
                if (!empty($this->socpeopleassigned)) {
1266
                    $already_inserted = array();
1267
                    foreach ($this->socpeopleassigned as $val) {
1268
                        if (!is_array($val)) {  // For backward compatibility when val=id
1269
                            $val = array('id' => $val);
1270
                        }
1271
                        if (!empty($already_inserted[$val['id']])) {
1272
                            continue;
1273
                        }
1274
1275
                        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "actioncomm_resources(fk_actioncomm, element_type, fk_element, mandatory, transparency, answer_status)";
1276
                        $sql .= " VALUES(" . ((int) $this->id) . ", 'socpeople', " . ((int) $val['id']) . ", 0, 0, 0)";
1277
1278
                        $resql = $this->db->query($sql);
1279
                        if (!$resql) {
1280
                            $error++;
1281
                            $this->errors[] = $this->db->lasterror();
1282
                        } else {
1283
                            $already_inserted[$val['id']] = true;
1284
                        }
1285
                    }
1286
                }
1287
            }
1288
1289
            if (!$error && !$notrigger) {
1290
                // Call trigger
1291
                $result = $this->call_trigger('ACTION_MODIFY', $user);
1292
                if ($result < 0) {
1293
                    $error++;
1294
                }
1295
                // End call triggers
1296
            }
1297
1298
            if (!$error) {
1299
                $this->db->commit();
1300
                return 1;
1301
            } else {
1302
                $this->db->rollback();
1303
                dol_syslog(get_only_class($this) . "::update " . implode(',', $this->errors), LOG_ERR);
1304
                return -2;
1305
            }
1306
        } else {
1307
            $this->db->rollback();
1308
            $this->error = $this->db->lasterror();
1309
            return -1;
1310
        }
1311
    }
1312
1313
    /**
1314
     *  Load all objects with filters.
1315
     *  @TODO WARNING: This make a fetch on all records instead of making one request with a join.
1316
     *
1317
     *  @param      int     $socid          Filter by thirdparty
1318
     *  @param      int     $fk_element     Id of element action is linked to
1319
     *  @param      string  $elementtype    Type of element action is linked to
1320
     *  @param      string  $filter         Other filter
1321
     *  @param      string  $sortfield      Sort on this field
1322
     *  @param      string  $sortorder      ASC or DESC
1323
     *  @param      int     $limit          Limit number of answers
1324
     *  @return     ActionComm[]|string     Error string if KO, array with actions if OK
1325
     */
1326
    public function getActions($socid = 0, $fk_element = 0, $elementtype = '', $filter = '', $sortfield = 'a.datep', $sortorder = 'DESC', $limit = 0)
1327
    {
1328
        global $hookmanager;
1329
1330
        $resarray = array();
1331
1332
        dol_syslog(get_only_class($this) . "::getActions", LOG_DEBUG);
1333
1334
        // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
1335
        if (!is_object($hookmanager)) {
1336
            $hookmanager = new HookManager($this->db);
1337
        }
1338
        $hookmanager->initHooks(array('agendadao'));
1339
1340
        $sql = "SELECT a.id";
1341
        $sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm as a";
1342
        // Fields from hook
1343
        $parameters = array('sql' => &$sql, 'socid' => $socid, 'fk_element' => $fk_element, 'elementtype' => $elementtype);
1344
        $reshook = $hookmanager->executeHooks('getActionsListFrom', $parameters);    // Note that $action and $object may have been modified by hook
1345
        if (!empty($hookmanager->resPrint)) {
1346
            $sql .= $hookmanager->resPrint;
1347
        }
1348
        $sql .= " WHERE a.entity IN (" . getEntity('agenda') . ")";
1349
        if (!empty($socid)) {
1350
            $sql .= " AND a.fk_soc = " . ((int) $socid);
1351
        }
1352
        if (!empty($elementtype)) {
1353
            if ($elementtype == 'project') {
1354
                $sql .= ' AND a.fk_project = ' . ((int) $fk_element);
1355
            } elseif ($elementtype == 'contact') {
1356
                $sql .= ' AND a.id IN';
1357
                $sql .= " (SELECT fk_actioncomm FROM " . MAIN_DB_PREFIX . "actioncomm_resources WHERE";
1358
                $sql .= " element_type = 'socpeople' AND fk_element = " . ((int) $fk_element) . ')';
1359
            } else {
1360
                $sql .= " AND a.fk_element = " . ((int) $fk_element) . " AND a.elementtype = '" . $this->db->escape($elementtype) . "'";
1361
            }
1362
        }
1363
        if (!empty($filter)) {
1364
            $sql .= $filter;
1365
        }
1366
        // Fields where hook
1367
        $parameters = array('sql' => &$sql, 'socid' => $socid, 'fk_element' => $fk_element, 'elementtype' => $elementtype);
1368
        $reshook = $hookmanager->executeHooks('getActionsListWhere', $parameters);    // Note that $action and $object may have been modified by hook
1369
        if (!empty($hookmanager->resPrint)) {
1370
            $sql .= $hookmanager->resPrint;
1371
        }
1372
        if ($sortorder && $sortfield) {
1373
            $sql .= $this->db->order($sortfield, $sortorder);
1374
        }
1375
        $sql .= $this->db->plimit($limit, 0);
1376
1377
        $resql = $this->db->query($sql);
1378
        if ($resql) {
1379
            $num = $this->db->num_rows($resql);
1380
1381
            if ($num) {
1382
                for ($i = 0; $i < $num; $i++) {
1383
                    $obj = $this->db->fetch_object($resql);
1384
                    $actioncommstatic = new ActionComm($this->db);
1385
                    $actioncommstatic->fetch($obj->id);
1386
                    $resarray[$i] = $actioncommstatic;
1387
                }
1388
            }
1389
            $this->db->free($resql);
1390
            return $resarray;
1391
        } else {
1392
            return $this->db->lasterror();
1393
        }
1394
    }
1395
1396
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1397
    /**
1398
     * Load indicators for dashboard (this->nbtodo and this->nbtodolate)
1399
     *
1400
     * @param   User    $user               Object user
1401
     * @param   int     $load_state_board   Load indicator array this->nb
1402
     * @return WorkboardResponse|int<-1,1>  Return integer <0 if KO, WorkboardResponse if OK
1403
     */
1404
    public function load_board($user, $load_state_board = 0)
1405
    {
1406
		// phpcs:enable
1407
        global $conf, $langs;
1408
1409
        if (empty($load_state_board)) {
1410
            $sql = "SELECT a.id, a.datep as dp";
1411
        } else {
1412
            $this->nb = array();
1413
            $sql = "SELECT count(a.id) as nb";
1414
        }
1415
        $sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm as a";
1416
        if (!$user->hasRight('agenda', 'allactions', 'read')) {
1417
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "actioncomm_resources AS ar ON a.id = ar.fk_actioncomm AND ar.element_type ='user' AND ar.fk_element = " . ((int) $user->id);
1418
        }
1419
        $sql .= " WHERE 1 = 1";
1420
        if (empty($load_state_board)) {
1421
            $sql .= " AND a.percent >= 0 AND a.percent < 100";
1422
        }
1423
        $sql .= " AND a.entity IN (" . getEntity('agenda') . ")";
1424
        if (!$user->hasRight('agenda', 'allactions', 'read')) {
1425
            $sql .= " AND (a.fk_user_author = " . ((int) $user->id) . " OR a.fk_user_action = " . ((int) $user->id);
1426
            $sql .= " OR ar.fk_element = " . ((int) $user->id);
1427
            $sql .= ")";
1428
        }
1429
        // If the internal user must only see his customers, force searching by him
1430
        $search_sale = 0;
1431
        if (!$user->hasRight('societe', 'client', 'voir')) {
1432
            $search_sale = $user->id;
1433
        }
1434
        // Search on sale representative
1435
        if ($search_sale && $search_sale != '-1') {
1436
            if ($search_sale == -2) {
1437
                $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = a.fk_soc)";
1438
            } elseif ($search_sale > 0) {
1439
                $sql .= " AND EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = a.fk_soc AND sc.fk_user = " . ((int) $search_sale) . ")";
1440
            }
1441
        }
1442
1443
        $resql = $this->db->query($sql);
1444
        if ($resql) {
1445
            $response = null;  // Ensure the variable is defined
1446
            if (empty($load_state_board)) {
1447
                $agenda_static = new ActionComm($this->db);
1448
                $response = new WorkboardResponse();
1449
                $response->warning_delay = $conf->agenda->warning_delay / 60 / 60 / 24;
1450
                $response->label = $langs->trans("ActionsToDo");
1451
                $response->labelShort = $langs->trans("ActionsToDoShort");
1452
                $response->url = constant('BASE_URL') . '/comm/action/list.php?mode=show_list&actioncode=0&status=todo&mainmenu=agenda';
1453
                if ($user->hasRight("agenda", "allactions", "read")) {
1454
                    $response->url .= '&filtert=-1';
1455
                }
1456
                $response->img = img_object('', "action", 'class="inline-block valigntextmiddle"');
1457
            }
1458
            // This assignment in condition is not a bug. It allows walking the results.
1459
            while ($obj = $this->db->fetch_object($resql)) {
1460
                if (empty($load_state_board)) {
1461
                    '@phan-var-force WorkboardResponse $response
1462
					 @phan-var-force ActionComm $agenda_static';
1463
                    $response->nbtodo++;
1464
                    $agenda_static->datep = $this->db->jdate($obj->dp);
1465
                    if ($agenda_static->hasDelay()) {
1466
                        $response->nbtodolate++;
1467
                    }
1468
                } else {
1469
                    $this->nb["actionscomm"] = $obj->nb;
1470
                }
1471
            }
1472
1473
            $this->db->free($resql);
1474
            if (empty($load_state_board) && $response instanceof WorkboardResponse) {
1475
                return $response;
1476
            } else {
1477
                return 1;
1478
            }
1479
        } else {
1480
            dol_print_error($this->db);
1481
            $this->error = $this->db->error();
1482
            return -1;
1483
        }
1484
    }
1485
1486
1487
    /**
1488
     *  Charge les information d'ordre info dans l'objet facture
1489
     *
1490
     *  @param  int     $id         Id de la facture a charger
1491
     *  @return void
1492
     */
1493
    public function info($id)
1494
    {
1495
        $sql = 'SELECT ';
1496
        $sql .= ' a.id,';
1497
        $sql .= ' datec,';
1498
        $sql .= ' tms as datem,';
1499
        $sql .= ' fk_user_author,';
1500
        $sql .= ' fk_user_mod';
1501
        $sql .= ' FROM ' . MAIN_DB_PREFIX . 'actioncomm as a';
1502
        $sql .= ' WHERE a.id = ' . ((int) $id);
1503
1504
        dol_syslog(get_only_class($this) . "::info", LOG_DEBUG);
1505
        $result = $this->db->query($sql);
1506
        if ($result) {
1507
            if ($this->db->num_rows($result)) {
1508
                $obj = $this->db->fetch_object($result);
1509
1510
                $this->id = $obj->id;
1511
1512
                $this->user_creation_id = $obj->fk_user_author;
1513
                $this->user_modification_id = $obj->fk_user_mod;
1514
                $this->date_creation     = $this->db->jdate($obj->datec);
1515
                $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1516
            }
1517
            $this->db->free($result);
1518
        } else {
1519
            dol_print_error($this->db);
1520
        }
1521
    }
1522
1523
1524
    /**
1525
     *  Return the label of the status
1526
     *
1527
     *  @param  int<0,7>    $mode           0=Long label, 1=Short label, 2=Picto+Short label, 3=Picto, 4=Picto+Short label, 5=Short label+Picto, 6=Picto+Long label, 7=Very short label+Picto
1528
     *  @param  int<0,1>    $hidenastatus   1=Show nothing if status is "Not applicable"
1529
     *  @return string                  String with status
1530
     */
1531
    public function getLibStatut($mode, $hidenastatus = 0)
1532
    {
1533
        return $this->LibStatut($this->percentage, $mode, $hidenastatus, $this->datep);
1534
    }
1535
1536
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1537
    /**
1538
     *  Return label of action status
1539
     *
1540
     *  @param  int<0,100>  $percent        Percent
1541
     *  @param  int<0,7>    $mode           0=Long label, 1=Short label, 2=Picto+Short label, 3=Picto, 4=Picto+Short label, 5=Short label+Picto, 6=Picto+Long label, 7=Very short label+Picto
1542
     *  @param  int<0,1>    $hidenastatus   1=Show nothing if status is "Not applicable"
1543
     *  @param  int|string  $datestart      Date start of event
1544
     *  @return string                      Label
1545
     */
1546
    public function LibStatut($percent, $mode, $hidenastatus = 0, $datestart = '')
1547
    {
1548
		// phpcs:enable
1549
        global $langs;
1550
1551
        $labelStatus = $langs->transnoentitiesnoconv('StatusNotApplicable');
1552
        if ($percent == -1 && !$hidenastatus) {
1553
            $labelStatus = $langs->transnoentitiesnoconv('StatusNotApplicable');
1554
        } elseif ($percent == 0) {
1555
            $labelStatus = $langs->transnoentitiesnoconv('StatusActionToDo') . ' (0%)';
1556
        } elseif ($percent > 0 && $percent < 100) {
1557
            $labelStatus = $langs->transnoentitiesnoconv('StatusActionInProcess') . ' (' . $percent . '%)';
1558
        } elseif ($percent >= 100) {
1559
            $labelStatus = $langs->transnoentitiesnoconv('StatusActionDone') . ' (100%)';
1560
        }
1561
1562
        $labelStatusShort = $langs->transnoentitiesnoconv('StatusNotApplicable');
1563
        if ($percent == -1 && !$hidenastatus) {
1564
            $labelStatusShort = $langs->trans('NA');
1565
        } elseif ($percent == 0) {
1566
            $labelStatusShort = '0%';
1567
        } elseif ($percent > 0 && $percent < 100) {
1568
            $labelStatusShort = $percent . '%';
1569
        } elseif ($percent >= 100) {
1570
            $labelStatusShort = '100%';
1571
        }
1572
1573
        $statusType = 'status9';
1574
        if ($percent == -1 && !$hidenastatus) {
1575
            $statusType = 'status9';
1576
        }
1577
        if ($percent == 0) {
1578
            $statusType = 'status1';
1579
        }
1580
        if ($percent > 0 && $percent < 100) {
1581
            $statusType = 'status3';
1582
        }
1583
        if ($percent >= 100) {
1584
            $statusType = 'status6';
1585
        }
1586
1587
        return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
1588
    }
1589
1590
    /**
1591
     * getTooltipContentArray
1592
     * @param array<string,mixed> $params params to construct tooltip data
1593
     * @since v18
1594
     * @return array{picto:string,ref?:string,title?:string,labeltype?:string,location?:string,transparency?:string,space?:string,mailtopic?:string,mailfrom?:string,mailto?:string,mailcc?:string,description?:string,note?:string,categories?:string}
1595
     */
1596
    public function getTooltipContentArray($params)
1597
    {
1598
        global $conf, $langs, $user;
1599
        $langs->load('agenda');
1600
1601
        $datas = array();
1602
        $nofetch = !empty($params['nofetch']);
1603
1604
        // Set label of type
1605
        $labeltype = '';
1606
        if ($this->type_code) {
1607
            $langs->load("commercial");
1608
            $labeltype = ($langs->transnoentities("Action" . $this->type_code) != "Action" . $this->type_code) ? $langs->transnoentities("Action" . $this->type_code) : $this->type_label;
1609
        }
1610
        if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
1611
            if ($this->type_code != 'AC_OTH_AUTO') {
1612
                $labeltype = $langs->trans('ActionAC_MANUAL');
1613
            }
1614
        }
1615
        $datas['picto'] = img_picto('', $this->picto) . ' <u>' . $langs->trans('Action') . '</u>';
1616
        if (!empty($this->ref)) {
1617
            $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . dol_escape_htmltag($this->ref);
1618
        }
1619
        if (!empty($this->label)) {
1620
            $datas['title'] = '<br><b>' . $langs->trans('Title') . ':</b> ' . dol_escape_htmltag($this->label);
1621
        }
1622
        if (!empty($labeltype)) {
1623
            $datas['labeltype'] = '<br><b>' . $langs->trans('Type') . ':</b> ' . dol_escape_htmltag($labeltype);
1624
        }
1625
        if (!empty($this->location)) {
1626
            $datas['location'] = '<br><b>' . $langs->trans('Location') . ':</b> ' . dol_escape_htmltag($this->location);
1627
        }
1628
        if (isset($this->transparency)) {
1629
            $datas['transparency'] = '<br><b>' . $langs->trans('Busy') . ':</b> ' . yn($this->transparency);
1630
        }
1631
        if (!empty($this->email_msgid)) {
1632
            $langs->load("mails");
1633
            $datas['space'] = '<br>';
1634
            // $datas['email'] = '<br><b>'.img_picto('', 'email').' '.$langs->trans("Email").'</b>';
1635
            $datas['mailtopic'] = '<br><b>' . $langs->trans('MailTopic') . ':</b> ' . dol_escape_htmltag($this->email_subject);
1636
            $datas['mailfrom'] = '<br><b>' . $langs->trans('MailFrom') . ':</b> ' . str_replace(array('<', '>'), array('&amp;lt', '&amp;gt'), $this->email_from);
1637
            $datas['mailto'] = '<br><b>' . $langs->trans('MailTo') . ':</b> ' . str_replace(array('<', '>'), array('&amp;lt', '&amp;gt'), $this->email_to);
1638
            if (!empty($this->email_tocc)) {
1639
                $datas['mailcc'] = '<br><b>' . $langs->trans('MailCC') . ':</b> ' . str_replace(array('<', '>'), array('&amp;lt', '&amp;gt'), $this->email_tocc);
1640
            }
1641
            /* Disabled because bcc must remain by definition not visible
1642
            if (!empty($this->email_tobcc)) {
1643
                $datas['mailccc'] = '<br><b>'.$langs->trans('MailCCC').':</b> '.$this->email_tobcc;
1644
            } */
1645
        }
1646
        if (!empty($this->note_private)) {
1647
            $datas['description'] = '<br><b>' . $langs->trans('Description') . ':</b><br>';
1648
            // Try to limit length of content
1649
            $texttoshow = dolGetFirstLineOfText($this->note_private, 10);
1650
            // Restrict height of content into the tooltip
1651
            $datas['note'] = '<div class="tenlinesmax">';
1652
            $datas['note'] .= (dol_textishtml($texttoshow) ? str_replace(array("\r", "\n"), "", $texttoshow) : str_replace(array("\r", "\n"), '<br>', $texttoshow));
1653
            $datas['note'] .= '</div>';
1654
        }
1655
        // show categories for this record only in ajax to not overload lists
1656
        if (isModEnabled('category') && !$nofetch) {
1657
            $form = new Form($this->db);
1658
            $datas['categories'] = '<br>' . $form->showCategories($this->id, Categorie::TYPE_ACTIONCOMM, 1);
1659
        }
1660
1661
        return $datas;
1662
    }
1663
1664
    /**
1665
     *  Return URL of event
1666
     *  Use $this->id, $this->type_code, $this->label and $this->type_label
1667
     *
1668
     *  @param  int<0,2>    $withpicto              0 = No picto, 1 = Include picto into link, 2 = Only picto
1669
     *  @param  int         $maxlength              Max number of characters into label. If negative, use the ref as label.
1670
     *  @param  string      $classname              Force style class on a link
1671
     *  @param  string      $option                 '' = Link to action, 'birthday'= Link to contact, 'holiday' = Link to leave
1672
     *  @param  int<0,1>    $overwritepicto         1 = Overwrite picto with this one
1673
     *  @param  int<0,1>    $notooltip              1 = Disable tooltip
1674
     *  @param  int<-1,1>   $save_lastsearch_value  -1 = Auto, 0 = No save of lastsearch_values when clicking, 1 = Save lastsearch_values whenclicking
1675
     *  @return string                          Chaine avec URL
1676
     */
1677
    public function getNomUrl($withpicto = 0, $maxlength = 0, $classname = '', $option = '', $overwritepicto = 0, $notooltip = 0, $save_lastsearch_value = -1)
1678
    {
1679
        global $conf, $langs, $user, $hookmanager, $action;
1680
1681
        if (!empty($conf->dol_no_mouse_hover)) {
1682
            $notooltip = 1; // Force disable tooltips
1683
        }
1684
1685
        $canread = 0;
1686
        if ($user->hasRight('agenda', 'myactions', 'read') && ($this->authorid == $user->id || $this->userownerid == $user->id)) {
1687
            $canread = 1; // Can read my event
1688
        }
1689
        if ($user->hasRight('agenda', 'myactions', 'read') && array_key_exists($user->id, $this->userassigned)) {
1690
            $canread = 1; // Can read my event i am assigned
1691
        }
1692
        if ($user->hasRight('agenda', 'allactions', 'read')) {
1693
            $canread = 1; // Can read all event of other
1694
        }
1695
        if (!$canread) {
1696
            $option = 'nolink';
1697
        }
1698
1699
        $label = $this->label;
1700
1701
        $result = '';
1702
1703
        // Set label of type
1704
        $labeltype = '';
1705
        if ($this->type_code) {
1706
            $langs->load("commercial");
1707
            $labeltype = ($langs->transnoentities("Action" . $this->type_code) != "Action" . $this->type_code) ? $langs->transnoentities("Action" . $this->type_code) : $this->type_label;
1708
        }
1709
        if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
1710
            if ($this->type_code != 'AC_OTH_AUTO') {
1711
                $labeltype = $langs->trans('ActionAC_MANUAL');
1712
            }
1713
        }
1714
1715
        $tooltip = img_picto('', $this->picto) . ' <u>' . $langs->trans('Action') . '</u>';
1716
        if (!empty($this->ref)) {
1717
            $tooltip .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . dol_escape_htmltag($this->ref);
1718
        }
1719
        if (!empty($label)) {
1720
            $tooltip .= '<br><b>' . $langs->trans('Title') . ':</b> ' . dol_escape_htmltag($label);
1721
        }
1722
        if (!empty($labeltype)) {
1723
            $tooltip .= '<br><b>' . $langs->trans('Type') . ':</b> ' . dol_escape_htmltag($labeltype);
1724
        }
1725
        if (!empty($this->location)) {
1726
            $tooltip .= '<br><b>' . $langs->trans('Location') . ':</b> ' . dol_escape_htmltag($this->location);
1727
        }
1728
        if (isset($this->transparency)) {
1729
            $tooltip .= '<br><b>' . $langs->trans('Busy') . ':</b> ' . yn($this->transparency);
1730
        }
1731
        if (!empty($this->email_msgid)) {
1732
            $langs->load("mails");
1733
            $tooltip .= '<br>';
1734
            //$tooltip .= '<br><b>'.img_picto('', 'email').' '.$langs->trans("Email").'</b>';
1735
            $tooltip .= '<br><b>' . $langs->trans('MailTopic') . ':</b> ' . dol_escape_htmltag($this->email_subject);
1736
            $tooltip .= '<br><b>' . $langs->trans('MailFrom') . ':</b> ' . str_replace(array('<', '>'), array('&amp;lt', '&amp;gt'), !empty($this->email_from) ? $this->email_from : '');
1737
            $tooltip .= '<br><b>' . $langs->trans('MailTo') . ':</b> ' . str_replace(array('<', '>'), array('&amp;lt', '&amp;gt'), !empty($this->email_to) ? $this->email_to : '');
1738
            if (!empty($this->email_tocc)) {
1739
                $tooltip .= '<br><b>' . $langs->trans('MailCC') . ':</b> ' . str_replace(array('<', '>'), array('&amp;lt', '&amp;gt'), $this->email_tocc);
1740
            }
1741
            /* Disabled because bcc must remain by definition not visible
1742
            if (!empty($this->email_tobcc)) {
1743
                $tooltip .= '<br><b>'.$langs->trans('MailCCC').':</b> '.$this->email_tobcc;
1744
            } */
1745
        }
1746
        if (!empty($this->note_private)) {
1747
            $tooltip .= '<br><br><b>' . $langs->trans('Description') . ':</b><br>';
1748
            $texttoshow = dolGetFirstLineOfText($this->note_private, 8);    // Try to limit length of content
1749
            $tooltip .= '<div class="tenlinesmax">';                        // Restrict height of content into the tooltip
1750
            $tooltip .= (dol_textishtml($texttoshow) ? str_replace(array("\r", "\n"), "", $texttoshow) : str_replace(array("\r", "\n"), '<br>', $texttoshow));
1751
            $tooltip .= '</div>';
1752
        }
1753
        $linkclose = '';
1754
        $classfortooltip = 'classfortooltip';
1755
        $dataparams = '';
1756
        if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1757
            $params = [
1758
                'id' => $this->id,
1759
                'objecttype' => $this->element,
1760
                'option' => $option,
1761
                'nofetch' => 1,
1762
            ];
1763
            $classfortooltip = 'classforajaxtooltip';
1764
            $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"';
1765
            $tooltip = '';
1766
        }
1767
        if (empty($notooltip)) {
1768
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1769
                $label = $langs->trans("ShowAction");
1770
                $linkclose .= ' alt="' . dol_escape_htmltag($tooltip, 1) . '"';
1771
            }
1772
            $linkclose .= ($tooltip ? ' title="' . dol_escape_htmltag($tooltip, 1) . '"' : ' title="tocomplete"');
1773
            $linkclose .= $dataparams . ' class="' . $classname . ' ' . $classfortooltip . '"';
1774
        } else {
1775
            $linkclose .= ' class="' . $classname . '"';
1776
        }
1777
1778
        $url = '';
1779
        if ($option == 'birthday') {
1780
            $url = constant('BASE_URL') . '/contact/perso.php?id=' . $this->id;
1781
        } elseif ($option == 'holiday') {
1782
            $url = constant('BASE_URL') . '/holiday/card.php?id=' . $this->id;
1783
        } else {
1784
            $url = constant('BASE_URL') . '/comm/action/card.php?id=' . $this->id;
1785
        }
1786
1787
        if ($option !== 'nolink') {
1788
            // Add param to save lastsearch_values or not
1789
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1790
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1791
                $add_save_lastsearch_values = 1;
1792
            }
1793
            if ($add_save_lastsearch_values) {
1794
                $url .= '&save_lastsearch_values=1';
1795
            }
1796
        }
1797
1798
        $linkstart = '<a href="' . $url . '"';
1799
        $linkstart .= $linkclose . '>';
1800
        $linkend = '</a>';
1801
1802
        if ($option == 'nolink') {
1803
            $linkstart = '';
1804
            $linkend = '';
1805
        }
1806
1807
        if ($withpicto == 2) {
1808
            if (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
1809
                $label = $labeltype;
1810
            }
1811
            $labelshort = '';
1812
        } else {
1813
            if (getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($label)) {
1814
                $label = $labeltype;
1815
            }
1816
            if ($maxlength < 0) {
1817
                $labelshort = $this->ref;
1818
            } else {
1819
                $labelshort = dol_trunc($label, $maxlength);
1820
            }
1821
        }
1822
1823
        if ($withpicto) {
1824
            if (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {  // Add code into ()
1825
                if ($labeltype) {
1826
                    $label .= (preg_match('/' . preg_quote($labeltype, '/') . '/', $label) ? '' : ' (' . $langs->transnoentities("Action" . $this->type_code) . ')');
1827
                }
1828
            }
1829
        }
1830
1831
        $result .= $linkstart;
1832
        if ($withpicto) {
1833
            $result .= img_object(($notooltip ? '' : $langs->trans("ShowAction") . ': ' . $label), ($overwritepicto ? $overwritepicto : 'action'), (($this->type_color && $overwritepicto) ? 'style="color: #' . $this->type_color . ' !important;" ' : '') . ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : ' class="' . (($withpicto != 2) ? 'paddingright ' : '') . '"'), 0, 0, $notooltip ? 0 : 1);
1834
        }
1835
        $result .= dol_escape_htmltag($labelshort);
1836
        $result .= $linkend;
1837
1838
        global $action;
1839
        $hookmanager->initHooks(array('actiondao'));
1840
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1841
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1842
        if ($reshook > 0) {
1843
            $result = $hookmanager->resPrint;
1844
        } else {
1845
            $result .= $hookmanager->resPrint;
1846
        }
1847
1848
        return $result;
1849
    }
1850
1851
    /**
1852
     *  Return Picto of type of event
1853
     *
1854
     *  @param  string      $morecss            More CSS
1855
     *  @param  string      $titlealt           Title alt
1856
     *  @return string                          HTML String
1857
     */
1858
    public function getTypePicto($morecss = 'pictofixedwidth paddingright valignmiddle', $titlealt = '')
1859
    {
1860
        global $conf;
1861
1862
        $imgpicto = '';
1863
        if (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
1864
            $color = '';
1865
            if ($this->type_color) {
1866
                $color = 'style="color: #' . $this->type_color . ' !important;"';
1867
            }
1868
            if ($this->type_picto) {
1869
                $imgpicto = img_picto($titlealt, $this->type_picto, '', false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1870
            } else {
1871
                if ($this->type_code == 'AC_RDV') {
1872
                    $imgpicto = img_picto($titlealt, 'meeting', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1873
                } elseif ($this->type_code == 'AC_TEL') {
1874
                    $imgpicto = img_picto($titlealt, 'object_phoning', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1875
                } elseif ($this->type_code == 'AC_FAX') {
1876
                    $imgpicto = img_picto($titlealt, 'object_phoning_fax', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1877
                } elseif ($this->type_code == 'AC_EMAIL' || $this->type_code == 'AC_EMAIL_IN' || (!empty($this->code) && preg_match('/_SENTBYMAIL/', $this->code))) {
1878
                    $imgpicto = img_picto($titlealt, 'object_email', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1879
                } elseif ($this->type_code == 'AC_INT') {
1880
                    $imgpicto = img_picto($titlealt, 'object_intervention', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1881
                } elseif (!empty($this->code) && preg_match('/^TICKET_MSG/', $this->code)) {
1882
                    $imgpicto = img_picto($titlealt, 'object_conversation', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1883
                } elseif ($this->type != 'systemauto') {
1884
                    $imgpicto = img_picto($titlealt, 'user-cog', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1885
                } else {
1886
                    $imgpicto = img_picto($titlealt, 'cog', $color, false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1887
                }
1888
            }
1889
        } else {
1890
            // 2 picto: 1 for auto, 1 for manual
1891
            if ($this->type != 'systemauto') {
1892
                $imgpicto = img_picto($titlealt, 'user-cog', '', false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1893
            } else {
1894
                $imgpicto = img_picto($titlealt, 'cog', '', false, 0, 0, '', ($morecss ? ' ' . $morecss : ''));
1895
            }
1896
        }
1897
1898
        return $imgpicto;
1899
    }
1900
1901
1902
    /**
1903
     * Sets object to supplied categories.
1904
     *
1905
     * Deletes object from existing categories not supplied.
1906
     * Adds it to non existing supplied categories.
1907
     * Existing categories are left untouch.
1908
     *
1909
     * @param  int[]|int    $categories     Category or categories IDs
1910
     * @return int<-1,1>                    Return integer <0 if KO, >0 if OK
1911
     */
1912
    public function setCategories($categories)
1913
    {
1914
        // Handle single category
1915
        if (!is_array($categories)) {
1916
            $categories = array($categories);
1917
        }
1918
1919
        // Get current categories
1920
        $c = new Categorie($this->db);
1921
        $existing = $c->containing($this->id, Categorie::TYPE_ACTIONCOMM, 'id');
1922
1923
        // Diff
1924
        if (is_array($existing)) {
1925
            $to_del = array_diff($existing, $categories);
1926
            $to_add = array_diff($categories, $existing);
1927
        } else {
1928
            $to_del = array(); // Nothing to delete
1929
            $to_add = $categories;
1930
        }
1931
1932
        // Process
1933
        foreach ($to_del as $del) {
1934
            if ($c->fetch($del) > 0) {
1935
                $c->del_type($this, Categorie::TYPE_ACTIONCOMM);
1936
            }
1937
        }
1938
        foreach ($to_add as $add) {
1939
            if ($c->fetch($add) > 0) {
1940
                $c->add_type($this, Categorie::TYPE_ACTIONCOMM);
1941
            }
1942
        }
1943
        return 1;
1944
    }
1945
1946
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1947
    /**
1948
     * Export events from database into a cal file.
1949
     *
1950
     * @param string    $format                     The format of the export 'vcal', 'ical/ics' or 'rss'
1951
     * @param string    $type                       The type of the export 'event' or 'journal'
1952
     * @param integer   $cachedelay                 Do not rebuild file if date older than cachedelay seconds
1953
     * @param string    $filename                   The name for the exported file.
1954
     * @param array<string,int|string>  $filters    Array of filters. Example array('notolderthan'=>99, 'year'=>..., 'idfrom'=>..., 'actiontype'=>'systemauto', 'actioncode'=>'AC_PRODUCT_MODIFY', 'project'=>123, ...)
1955
     * @param int<0,1>  $exportholiday              0 = don't integrate holidays into the export, 1 = integrate holidays into the export
1956
     * @return int<-1,1>                            -1 = error on build export file, 0 = export okay
1957
     */
1958
    public function build_exportfile($format, $type, $cachedelay, $filename, $filters, $exportholiday = 0)
1959
    {
1960
        global $hookmanager;
1961
1962
		// phpcs:enable
1963
        global $conf, $langs, $dolibarr_main_url_root, $mysoc;
1964
1965
        require_once DOL_DOCUMENT_ROOT . "/core/lib/xcal.lib.php";
1966
        require_once DOL_DOCUMENT_ROOT . "/core/lib/date.lib.php";
1967
        require_once DOL_DOCUMENT_ROOT . "/core/lib/files.lib.php";
1968
1969
        dol_syslog(get_only_class($this) . "::build_exportfile Build export file format=" . $format . ", type=" . $type . ", cachedelay=" . $cachedelay . ", filename=" . $filename . ", filters size=" . count($filters), LOG_DEBUG);
1970
1971
        // Check parameters
1972
        if (empty($format)) {
1973
            return -1;
1974
        }
1975
1976
        // Clean parameters
1977
        if (!$filename) {
1978
            $extension = 'vcs';
1979
            if ($format == 'ical') {
1980
                $extension = 'ics';
1981
            }
1982
            $filename = $format . '.' . $extension;
1983
        }
1984
1985
        // Create dir and define output file (definitive and temporary)
1986
        $result = dol_mkdir($conf->agenda->dir_temp);
1987
        $outputfile = $conf->agenda->dir_temp . '/' . $filename;
1988
1989
        $result = 0;
1990
1991
        $buildfile = true;
1992
        $login = '';
1993
        $logina = '';
1994
        $logint = '';
1995
        $eventorganization = '';
1996
1997
        $now = dol_now();
1998
1999
        if ($cachedelay) {
2000
            $nowgmt = dol_now();
2001
            include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
2002
            if (dol_filemtime($outputfile) > ($nowgmt - $cachedelay)) {
2003
                dol_syslog(get_only_class($this) . "::build_exportfile file " . $outputfile . " is not older than now - cachedelay (" . $nowgmt . " - " . $cachedelay . "). Build is canceled");
2004
                $buildfile = false;
2005
            }
2006
        }
2007
2008
        if ($buildfile) {
2009
            // Build event array
2010
            $eventarray = array();
2011
2012
            if (!empty($filters['module']) && $filters['module'] == 'project@eventorganization') {
2013
                $sql = "SELECT p.rowid as id,";
2014
                $sql .= " p.date_start_event as datep,"; // Start
2015
                $sql .= " p.date_end_event as datep2,"; // End
2016
                $sql .= " p.datec, p.tms as datem,";
2017
                $sql .= " p.title as label, '' as code, p.note_public, p.note_private, 0 as type_id,";
2018
                $sql .= " p.fk_soc,";
2019
                $sql .= " p.fk_user_creat as fk_user_author, p.fk_user_modif as fk_user_mod,";
2020
                $sql .= " 0 as fk_user_action,";
2021
                $sql .= " 0 as fk_contact, 100 as percentage,";
2022
                $sql .= " 0 as fk_element, '' as elementtype,";
2023
                $sql .= " 1 as priority, 0 as fulldayevent, p.location, 0 as transparency,";
2024
                $sql .= " u.firstname, u.lastname, '" . $this->db->escape(getDolGlobalString("MAIN_INFO_SOCIETE_MAIL")) . "' as email,";
2025
                $sql .= " s.nom as socname,";
2026
                $sql .= " 0 as type_id, '' as type_code, '' as type_label";
2027
                $sql .= " FROM " . MAIN_DB_PREFIX . "projet as p";
2028
                $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as u on u.rowid = p.fk_user_creat"; // Link to get author of event for export
2029
                $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s on s.rowid = p.fk_soc";
2030
2031
                $parameters = array('filters' => $filters);
2032
                $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters); // Note that $action and $object may have been modified by hook
2033
                $sql .= $hookmanager->resPrint;
2034
2035
                $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
2036
2037
                foreach ($filters as $key => $value) {
2038
                    if ($key == 'notolderthan' && $value != '') {
2039
                        $sql .= " AND p.date_start_event >= '" . $this->db->idate($now - ($value * 24 * 60 * 60)) . "'";
2040
                    }
2041
                    if ($key == 'year') {
2042
                        $sql .= " AND p.date_start_event BETWEEN '" . $this->db->idate(dol_get_first_day($value, 1)) . "' AND '" . $this->db->idate(dol_get_last_day($value, 12)) . "'";
2043
                    }
2044
                    if ($key == 'id') {
2045
                        $sql .= " AND p.id = " . (is_numeric($value) ? $value : 0);
2046
                    }
2047
                    if ($key == 'idfrom') {
2048
                        $sql .= " AND p.id >= " . (is_numeric($value) ? $value : 0);
2049
                    }
2050
                    if ($key == 'idto') {
2051
                        $sql .= " AND p.id <= " . (is_numeric($value) ? $value : 0);
2052
                    }
2053
                    if ($key == 'project') {
2054
                        $sql .= " AND p.rowid = " . (is_numeric($value) ? $value : 0);
2055
                    }
2056
                    if ($key == 'status') {
2057
                        $sql .= " AND p.fk_statut = " . ((int) $value);
2058
                    }
2059
                    // TODO Add filters on event code of meetings/talks only
2060
                }
2061
2062
                $sql .= " ORDER by date_start_event";
2063
2064
                $eventorganization = 'project';
2065
            } else {
2066
                $sql = "SELECT a.id,";
2067
                $sql .= " a.datep,"; // Start
2068
                $sql .= " a.datep2,"; // End
2069
                $sql .= " a.datec, a.tms as datem,";
2070
                $sql .= " a.label, a.code, '' as note_public, a.note as note_private, a.fk_action as type_id,";
2071
                $sql .= " a.fk_soc,";
2072
                $sql .= " a.fk_user_author, a.fk_user_mod,";
2073
                $sql .= " a.fk_user_action,";
2074
                $sql .= " a.fk_contact, a.percent as percentage,";
2075
                $sql .= " a.fk_element, a.elementtype,";
2076
                $sql .= " a.priority, a.fulldayevent, a.location, a.transparency,";
2077
                $sql .= " u.firstname, u.lastname, u.email,";
2078
                $sql .= " s.nom as socname,";
2079
                $sql .= " c.id as type_id, c.code as type_code, c.libelle as type_label,";
2080
                $sql .= " num_vote, event_paid, a.status";
2081
                $sql .= " FROM (" . MAIN_DB_PREFIX . "c_actioncomm as c, " . MAIN_DB_PREFIX . "actioncomm as a)";
2082
                $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "user as u on u.rowid = a.fk_user_author"; // Link to get author of event for export
2083
                $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s on s.rowid = a.fk_soc";
2084
2085
                $parameters = array('filters' => $filters);
2086
                $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters); // Note that $action and $object may have been modified by hook
2087
                $sql .= $hookmanager->resPrint;
2088
2089
                // We must filter on assignment table
2090
                if (!empty($filters['logint']) && $filters['logint']) {
2091
                    $sql .= ", " . MAIN_DB_PREFIX . "actioncomm_resources as ar";
2092
                }
2093
                $sql .= " WHERE a.fk_action = c.id";
2094
                $sql .= " AND a.entity IN (" . getEntity('agenda') . ")";
2095
2096
                foreach ($filters as $key => $value) {
2097
                    if ($key == 'notolderthan' && $value != '') {
2098
                        $sql .= " AND a.datep >= '" . $this->db->idate($now - ($value * 24 * 60 * 60)) . "'";
2099
                    }
2100
                    if ($key == 'year') {
2101
                        $sql .= " AND a.datep BETWEEN '" . $this->db->idate(dol_get_first_day($value, 1)) . "' AND '" . $this->db->idate(dol_get_last_day($value, 12)) . "'";
2102
                    }
2103
                    if ($key == 'id') {
2104
                        $sql .= " AND a.id = " . (is_numeric($value) ? $value : 0);
2105
                    }
2106
                    if ($key == 'idfrom') {
2107
                        $sql .= " AND a.id >= " . (is_numeric($value) ? $value : 0);
2108
                    }
2109
                    if ($key == 'idto') {
2110
                        $sql .= " AND a.id <= " . (is_numeric($value) ? $value : 0);
2111
                    }
2112
                    if ($key == 'project') {
2113
                        $sql .= " AND a.fk_project = " . (is_numeric($value) ? $value : 0);
2114
                    }
2115
                    if ($key == 'notactiontype') {  // deprecated
2116
                        $sql .= " AND c.type <> '" . $this->db->escape($value) . "'";
2117
                    }
2118
                    if ($key == 'actiontype') { // 'system', 'systemauto', 'module', ...
2119
                        $newvalue = $value;
2120
                        $usenotin = 0;
2121
                        if (preg_match('/^!/', $newvalue)) {
2122
                            $newvalue = preg_replace('/^!/', '', $value);
2123
                            $usenotin = 1;
2124
                        }
2125
                        $arraynewvalue = explode(',', $newvalue);
2126
                        $newvalue = "";
2127
                        foreach ($arraynewvalue as $tmpval) {
2128
                            $newvalue .= ($newvalue ? "," : "") . "'" . $tmpval . "'";
2129
                        }
2130
                        if ($usenotin) {
2131
                            $sql .= " AND c.type NOT IN (" . $this->db->sanitize($newvalue, 1) . ")";
2132
                        } else {
2133
                            $sql .= " AND c.type IN (" . $this->db->sanitize($newvalue, 1) . ")";
2134
                        }
2135
                    }
2136
                    if ($key == 'actioncode') { // 'AC_COMPANY_CREATE', 'AC_COMPANY_MODIFY', ...
2137
                        $newvalue = $value;
2138
                        $usenotin = 0;
2139
                        if (preg_match('/^!/', $newvalue)) {
2140
                            $newvalue = preg_replace('/^!/', '', $value);
2141
                            $usenotin = 1;
2142
                        }
2143
                        $arraynewvalue = explode(',', $newvalue);
2144
                        $newvalue = "";
2145
                        foreach ($arraynewvalue as $tmpval) {
2146
                            $newvalue .= ($newvalue ? "," : "") . "'" . $tmpval . "'";
2147
                        }
2148
                        if ($usenotin) {
2149
                            $sql .= " AND a.code NOT IN (" . $this->db->sanitize($newvalue, 1) . ")";
2150
                        } else {
2151
                            $sql .= " AND a.code IN (" . $this->db->sanitize($newvalue, 1) . ")";
2152
                        }
2153
                    }
2154
2155
                    // We must filter on assignment table
2156
                    if ($key == 'logint') {
2157
                        $sql .= " AND ar.fk_actioncomm = a.id AND ar.element_type='user'";
2158
                    }
2159
                    if ($key == 'logina') {
2160
                        $logina = $value;
2161
                        $condition = '=';
2162
                        if (preg_match('/^!/', $logina)) {
2163
                            $logina = preg_replace('/^!/', '', $logina);
2164
                            $condition = '<>';
2165
                        }
2166
                        $userforfilter = new User($this->db);
2167
                        $result = $userforfilter->fetch(0, $logina);
2168
                        if ($result > 0) {
2169
                            $sql .= " AND a.fk_user_author " . $condition . " " . $userforfilter->id;
2170
                        } elseif ($result < 0 || $condition == '=') {
2171
                            $sql .= " AND a.fk_user_author = 0";
2172
                        }
2173
                    }
2174
                    if ($key == 'logint') {
2175
                        $logint = $value;
2176
                        $condition = '=';
2177
                        if (preg_match('/^!/', $logint)) {
2178
                            $logint = preg_replace('/^!/', '', $logint);
2179
                            $condition = '<>';
2180
                        }
2181
                        $userforfilter = new User($this->db);
2182
                        $result = $userforfilter->fetch(0, $logint);
2183
                        if ($result > 0) {
2184
                            $sql .= " AND ar.fk_element = " . ((int) $userforfilter->id);
2185
                        } elseif ($result < 0 || $condition == '=') {
2186
                            $sql .= " AND ar.fk_element = 0";
2187
                        }
2188
                    }
2189
                    if ($key == 'module') {
2190
                        if ($value == 'conforbooth@eventorganization') {
2191
                            $value = '@eventorganization';
2192
                        }
2193
                        $sql .= " AND c.module LIKE '%" . $this->db->escape($value) . "'";
2194
                    }
2195
                    if ($key == 'status') {
2196
                        $sql .= " AND a.status = " . ((int) $value);
2197
                    }
2198
                }
2199
2200
                $sql .= " AND a.datep IS NOT NULL"; // To exclude corrupted events and avoid errors in lightning/sunbird import
2201
2202
                $parameters = array('filters' => $filters);
2203
                $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
2204
                $sql .= $hookmanager->resPrint;
2205
2206
                $sql .= " ORDER by datep";
2207
            }
2208
2209
            if (!empty($filters['limit'])) {
2210
                $sql .= $this->db->plimit((int) $filters['limit']);
2211
            }
2212
2213
            //print $sql;exit;
2214
2215
            dol_syslog(get_only_class($this) . "::build_exportfile select event(s)", LOG_DEBUG);
2216
2217
            $resql = $this->db->query($sql);
2218
            if ($resql) {
2219
                $diff = 0;
2220
                while ($obj = $this->db->fetch_object($resql)) {
2221
                    $qualified = true;
2222
2223
                    // 'eid','startdate','duration','enddate','title','summary','category','email','url','desc','author'
2224
                    $event = array();
2225
                    $event['uid'] = 'dolibarragenda-' . $this->db->database_name . '-' . $obj->id . "@" . $_SERVER["SERVER_NAME"];
2226
                    $event['type'] = $type;
2227
2228
                    $datestart = $this->db->jdate($obj->datep) - (!getDolGlobalString('AGENDA_EXPORT_FIX_TZ') ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
2229
2230
                    // fix for -> Warning: A non-numeric value encountered
2231
                    if (is_numeric($this->db->jdate($obj->datep2))) {
2232
                        $dateend = $this->db->jdate($obj->datep2) - (!getDolGlobalString('AGENDA_EXPORT_FIX_TZ') ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
2233
                    } else {
2234
                        // use start date as fall-back to avoid pb with empty end date on ICS readers
2235
                        $dateend = $datestart;
2236
                    }
2237
2238
                    $duration = ($datestart && $dateend) ? ($dateend - $datestart) : 0;
2239
                    $event['summary'] = $obj->label . ($obj->socname ? " (" . $obj->socname . ")" : "");
2240
2241
                    if (!empty($filters['module']) && $filters['module'] == 'project@eventorganization') {
2242
                        $event['desc'] = $obj->note_public;
2243
                    } else {
2244
                        $event['desc'] = $obj->note_private;
2245
                    }
2246
                    $event['startdate'] = $datestart;
2247
                    $event['enddate'] = $dateend; // Not required with type 'journal'
2248
                    $event['duration'] = $duration; // Not required with type 'journal'
2249
                    $event['author'] = dolGetFirstLastname($obj->firstname, $obj->lastname);
2250
                    $event['priority'] = $obj->priority;
2251
                    $event['fulldayevent'] = $obj->fulldayevent;
2252
                    $event['location'] = $obj->location;
2253
                    $event['transparency'] = (($obj->transparency > 0) ? 'OPAQUE' : 'TRANSPARENT'); // OPAQUE (busy) or TRANSPARENT (not busy)
2254
                    $event['category'] = $obj->type_label;
2255
                    $event['email'] = $obj->email;
2256
2257
                    // Public URL of event
2258
                    if ($eventorganization != '') {
2259
                        $link_subscription = $dolibarr_main_url_root . '/public/eventorganization/attendee_new.php?id=' . ((int) $obj->id) . '&type=global&noregistration=1';
2260
                        $encodedsecurekey = dol_hash(getDolGlobalString('EVENTORGANIZATION_SECUREKEY') . 'conferenceorbooth' . ((int) $obj->id), 'md5');
2261
                        $link_subscription .= '&securekey=' . urlencode($encodedsecurekey);
2262
2263
                        $event['url'] = $link_subscription;
2264
                    }
2265
2266
                    $event['created'] = $this->db->jdate($obj->datec) - (!getDolGlobalString('AGENDA_EXPORT_FIX_TZ') ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
2267
                    $event['modified'] = $this->db->jdate($obj->datem) - (!getDolGlobalString('AGENDA_EXPORT_FIX_TZ') ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
2268
                    $event['num_vote'] = $this->num_vote;
2269
                    $event['event_paid'] = $this->event_paid;
2270
                    $event['status'] = $this->status;
2271
2272
                    // TODO: find a way to call "$this->fetch_userassigned();" without override "$this" properties
2273
                    $this->id = $obj->id;
2274
                    $this->fetch_userassigned(false);
2275
2276
                    $assignedUserArray = array();
2277
2278
                    foreach ($this->userassigned as $key => $value) {
2279
                        $assignedUser = new User($this->db);
2280
                        $assignedUser->fetch($value['id']);
2281
2282
                        $assignedUserArray[$key] = $assignedUser;
2283
                    }
2284
2285
                    $event['assignedUsers'] = $assignedUserArray;
2286
2287
                    if ($qualified && $datestart) {
2288
                        $eventarray[] = $event;
2289
                    }
2290
                    $diff++;
2291
                }
2292
2293
                $parameters = array('filters' => $filters, 'eventarray' => &$eventarray);
2294
                $reshook = $hookmanager->executeHooks('addMoreEventsExport', $parameters); // Note that $action and $object may have been modified by hook
2295
                if ($reshook > 0) {
2296
                    $eventarray = $hookmanager->resArray;
2297
                }
2298
            } else {
2299
                $this->error = $this->db->lasterror();
2300
                return -1;
2301
            }
2302
2303
            if ($exportholiday == 1) {
2304
                $langs->load("holiday");
2305
                $title = $langs->transnoentities("Holidays");
2306
2307
                $sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.email, u.statut, x.rowid, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.statut as status";
2308
                $sql .= " FROM " . MAIN_DB_PREFIX . "holiday as x, " . MAIN_DB_PREFIX . "user as u";
2309
                $sql .= " WHERE u.rowid = x.fk_user";
2310
                $sql .= " AND u.statut = '1'"; // Show only active users  (0 = inactive user, 1 = active user)
2311
                $sql .= " AND (x.statut = '2' OR x.statut = '3')"; // Show only public leaves (2 = leave wait for approval, 3 = leave approved)
2312
2313
                $resql = $this->db->query($sql);
2314
                if ($resql) {
2315
                    $num = $this->db->num_rows($resql);
2316
                    $i   = 0;
2317
2318
                    while ($i < $num) {
2319
                        $obj   = $this->db->fetch_object($resql);
2320
                        $event = array();
2321
2322
                        if ($obj->halfday == 1) {
2323
                            $event['fulldayevent'] = false;
2324
2325
                            $timestampStart = dol_stringtotime($obj->date_start . " 00:00:00", 0);
2326
                            $timestampEnd   = dol_stringtotime($obj->date_end . " 12:00:00", 0);
2327
                        } elseif ($obj->halfday == -1) {
2328
                            $event['fulldayevent'] = false;
2329
2330
                            $timestampStart = dol_stringtotime($obj->date_start . " 12:00:00", 0);
2331
                            $timestampEnd   = dol_stringtotime($obj->date_end . " 23:59:59", 0);
2332
                        } else {
2333
                            $event['fulldayevent'] = true;
2334
2335
                            $timestampStart = dol_stringtotime($obj->date_start . " 00:00:00", 0);
2336
                            $timestampEnd   = dol_stringtotime($obj->date_end . " 23:59:59", 0);
2337
                        }
2338
2339
                        if (getDolGlobalString('AGENDA_EXPORT_FIX_TZ')) {
2340
                            $timestampStart -= ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600);
2341
                            $timestampEnd   -= ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600);
2342
                        }
2343
2344
                        $urlwithouturlroot = preg_replace('/' . preg_quote(DOL_URL_ROOT, '/') . '$/i', '', trim($dolibarr_main_url_root));
2345
                        $urlwithroot       = $urlwithouturlroot . DOL_URL_ROOT;
2346
                        $url               = $urlwithroot . '/holiday/card.php?id=' . $obj->rowid;
2347
2348
                        $event['uid']          = 'dolibarrholiday-' . $this->db->database_name . '-' . $obj->rowid . "@" . $_SERVER["SERVER_NAME"];
2349
                        $event['author']       = dolGetFirstLastname($obj->firstname, $obj->lastname);
2350
                        $event['type']         = 'event';
2351
                        $event['category']     = "Holiday";
2352
                        $event['transparency'] = 'OPAQUE';
2353
                        $event['email']        = $obj->email;
2354
                        $event['created']      = $timestampStart;
2355
                        $event['modified']     = $timestampStart;
2356
                        $event['startdate']    = $timestampStart;
2357
                        $event['enddate']      = $timestampEnd;
2358
                        $event['duration']     = $timestampEnd - $timestampStart;
2359
                        $event['url']          = $url;
2360
2361
                        if ($obj->status == 2) {
2362
                            // 2 = leave wait for approval
2363
                            $event['summary'] = $title . " - " . $obj->lastname . " (wait for approval)";
2364
                        } else {
2365
                            // 3 = leave approved
2366
                            $event['summary'] = $title . " - " . $obj->lastname;
2367
                        }
2368
2369
                        $eventarray[] = $event;
2370
2371
                        $i++;
2372
                    }
2373
                }
2374
            }
2375
2376
            $langs->load("agenda");
2377
2378
            // Define title and desc
2379
            $title = '';
2380
            $more = '';
2381
            if ($login) {
2382
                $more = $langs->transnoentities("User") . ' ' . $login;
2383
            }
2384
            if ($logina) {
2385
                $more = $langs->transnoentities("ActionsAskedBy") . ' ' . $logina;
2386
            }
2387
            if ($logint) {
2388
                $more = $langs->transnoentities("ActionsToDoBy") . ' ' . $logint;
2389
            }
2390
            if ($eventorganization) {
2391
                $langs->load("eventorganization");
2392
                $title = $langs->transnoentities("OrganizedEvent") . (empty($eventarray[0]['label']) ? '' : ' ' . $eventarray[0]['label']);
2393
                $more = 'ICS file - ' . $langs->transnoentities("OrganizedEvent") . (empty($eventarray[0]['label']) ? '' : ' ' . $eventarray[0]['label']);
2394
            }
2395
            if ($more) {
2396
                if (empty($title)) {
2397
                    $title = 'Dolibarr actions ' . $mysoc->name . ' - ' . $more;
2398
                }
2399
                $desc = $more;
2400
                $desc .= ' (' . $mysoc->name . ' - built by Dolibarr)';
2401
            } else {
2402
                if (empty($title)) {
2403
                    $title = 'Dolibarr actions ' . $mysoc->name;
2404
                }
2405
                $desc = $langs->transnoentities('ListOfActions');
2406
                $desc .= ' (' . $mysoc->name . ' - built by Dolibarr)';
2407
            }
2408
2409
            // Create temp file
2410
            $outputfiletmp = tempnam($conf->agenda->dir_temp, 'tmp'); // Temporary file (allow call of function by different threads
2411
            dolChmod($outputfiletmp);
2412
2413
            // Write file
2414
            if ($format == 'vcal') {
2415
                $result = build_calfile($format, $title, $desc, $eventarray, $outputfiletmp);
2416
            } elseif ($format == 'ical') {
2417
                $result = build_calfile($format, $title, $desc, $eventarray, $outputfiletmp);
2418
            } elseif ($format == 'rss') {
2419
                $result = build_rssfile($format, $title, $desc, $eventarray, $outputfiletmp);
2420
            }
2421
2422
            if ($result >= 0) {
2423
                if (dol_move($outputfiletmp, $outputfile, 0, 1, 0, 0)) {
2424
                    $result = 1;
2425
                } else {
2426
                    $this->error = 'Failed to rename ' . $outputfiletmp . ' into ' . $outputfile;
2427
                    dol_syslog(get_only_class($this) . "::build_exportfile " . $this->error, LOG_ERR);
2428
                    dol_delete_file($outputfiletmp, 0, 1);
2429
                    $result = -1;
2430
                }
2431
            } else {
2432
                dol_syslog(get_only_class($this) . "::build_exportfile build_xxxfile function fails to for format=" . $format . " outputfiletmp=" . $outputfile, LOG_ERR);
2433
                dol_delete_file($outputfiletmp, 0, 1);
2434
                $langs->load("errors");
2435
                $this->error = $langs->trans("ErrorFailToCreateFile", $outputfile);
2436
            }
2437
        }
2438
2439
        return $result;
2440
    }
2441
2442
    /**
2443
     *  Initialise an instance with random values.
2444
     *  Used to build previews or test instances.
2445
     *  id must be 0 if object instance is a specimen.
2446
     *
2447
     *  @return int<1,1>     >0 if ok
2448
     */
2449
    public function initAsSpecimen()
2450
    {
2451
        global $user;
2452
2453
        $now = dol_now();
2454
2455
        // Initialise parameters
2456
        $this->id = 0;
2457
        $this->specimen = 1;
2458
2459
        $this->type_code = 'AC_OTH';
2460
        $this->code = 'AC_SPECIMEN_CODE';
2461
        $this->label = 'Label of event Specimen';
2462
        $this->datec = $now;
2463
        $this->datem = $now;
2464
        $this->datep = $now;
2465
        $this->datef = $now;
2466
        $this->fulldayevent = 0;
2467
        $this->percentage = 0;
2468
        $this->status = 0;
2469
        $this->location = 'Location';
2470
        $this->transparency = 1; // 1 means opaque
2471
        $this->priority = 1;
2472
        //$this->note_public = "This is a 'public' note.";
2473
        $this->note_private = "This is a 'private' note.";
2474
2475
        $this->userownerid = $user->id;
2476
        $this->userassigned[$user->id] = array('id' => $user->id, 'transparency' => 1);
2477
        return 1;
2478
    }
2479
2480
    /**
2481
     *  Function used to replace a thirdparty id with another one.
2482
     *
2483
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
2484
     * @param   int     $origin_id  Old thirdparty id
2485
     * @param   int     $dest_id    New thirdparty id
2486
     * @return  bool
2487
     */
2488
    public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
2489
    {
2490
        $tables = array(
2491
            'actioncomm'
2492
        );
2493
2494
        return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
2495
    }
2496
2497
    /**
2498
     *  Function used to replace a product id with another one.
2499
     *
2500
     *  @param DoliDB $dbs Database handler
2501
     *  @param int $origin_id Old product id
2502
     *  @param int $dest_id New product id
2503
     *  @return bool
2504
     */
2505
    public static function replaceProduct(DoliDB $dbs, $origin_id, $dest_id)
2506
    {
2507
        $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'actioncomm SET fk_element = ' . ((int) $dest_id) . ' WHERE elementtype="product" AND fk_element = ' . ((int) $origin_id);
2508
        // using $dbs, not $this->db because function is static
2509
        if (!$dbs->query($sql)) {
2510
            //$this->errors = $dbs->lasterror();
2511
            return false;
2512
        }
2513
2514
        return true;
2515
    }
2516
2517
    /**
2518
     *  Is the action delayed?
2519
     *
2520
     *  @return bool
2521
     */
2522
    public function hasDelay()
2523
    {
2524
        global $conf;
2525
2526
        $now = dol_now();
2527
2528
        return $this->datep && ($this->datep < ($now - $conf->agenda->warning_delay));
2529
    }
2530
2531
2532
    /**
2533
     *  Load event reminder of events
2534
     *
2535
     *  @param  string  $type       Type of reminder 'browser' or 'email'
2536
     *  @param  int     $fk_user    Id of user
2537
     *  @param  bool    $onlypast   true = get only past reminder, false = get all reminders linked to this
2538
     *  @return int<-1,max>         < if OK, else count of number of reminders
2539
     */
2540
    public function loadReminders($type = '', $fk_user = 0, $onlypast = true)
2541
    {
2542
        global $conf, $langs, $user;
2543
2544
        $error = 0;
2545
2546
        $this->reminders = array();
2547
2548
        //Select all action comm reminders for event
2549
        $sql = "SELECT rowid as id, typeremind, dateremind, status, offsetvalue, offsetunit, fk_user, fk_email_template, lasterror";
2550
        $sql .= " FROM " . MAIN_DB_PREFIX . "actioncomm_reminder";
2551
        $sql .= " WHERE fk_actioncomm = " . ((int) $this->id);
2552
        if ($onlypast) {
2553
            $sql .= " AND dateremind <= '" . $this->db->idate(dol_now()) . "'";
2554
        }
2555
        if ($type) {
2556
            $sql .= " AND typeremind = '" . $this->db->escape($type) . "'";
2557
        }
2558
        if ($fk_user > 0) {
2559
            $sql .= " AND fk_user = " . ((int) $fk_user);
2560
        }
2561
        if (!getDolGlobalString('AGENDA_REMINDER_EMAIL')) {
2562
            $sql .= " AND typeremind <> 'email'";
2563
        }
2564
        if (!getDolGlobalString('AGENDA_REMINDER_BROWSER')) {
2565
            $sql .= " AND typeremind <> 'browser'";
2566
        }
2567
2568
        $sql .= $this->db->order("dateremind", "ASC");
2569
        $resql = $this->db->query($sql);
2570
2571
        if ($resql) {
2572
            while ($obj = $this->db->fetch_object($resql)) {
2573
                $tmpactioncommreminder = new ActionCommReminder($this->db);
2574
                $tmpactioncommreminder->id = $obj->id;
2575
                $tmpactioncommreminder->typeremind = $obj->typeremind;
2576
                $tmpactioncommreminder->dateremind = $obj->dateremind;
2577
                $tmpactioncommreminder->offsetvalue = $obj->offsetvalue;
2578
                $tmpactioncommreminder->offsetunit = $obj->offsetunit;
2579
                $tmpactioncommreminder->status = $obj->status;
2580
                $tmpactioncommreminder->fk_user = $obj->fk_user;
2581
                $tmpactioncommreminder->fk_email_template = $obj->fk_email_template;
2582
                $tmpactioncommreminder->lasterror = $obj->lasterror;
2583
2584
                $this->reminders[$obj->id] = $tmpactioncommreminder;
2585
            }
2586
        } else {
2587
            $this->error = $this->db->lasterror();
2588
            $error++;
2589
        }
2590
2591
        return count($this->reminders);
2592
    }
2593
2594
2595
    /**
2596
     *  Send reminders by emails
2597
     *  CAN BE A CRON TASK
2598
     *
2599
     *  @return int<-1,1>|string     0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
2600
     */
2601
    public function sendEmailsReminder()
2602
    {
2603
        global $conf, $langs, $user;
2604
2605
        $error = 0;
2606
        $this->output = '';
2607
        $this->error = '';
2608
        $nbMailSend = 0;
2609
        $errorsMsg = array();
2610
2611
        if (!isModEnabled('agenda')) {  // Should not happen. If module disabled, cron job should not be visible.
2612
            $langs->load("agenda");
2613
            $this->output = $langs->trans('ModuleNotEnabled', $langs->transnoentitiesnoconv("Agenda"));
2614
            return 0;
2615
        }
2616
        if (!getDolGlobalString('AGENDA_REMINDER_EMAIL')) {
2617
            $langs->load("agenda");
2618
            $this->output = $langs->trans('EventRemindersByEmailNotEnabled', $langs->transnoentitiesnoconv("Agenda"));
2619
            return 0;
2620
        }
2621
2622
        $now = dol_now();
2623
        $actionCommReminder = new ActionCommReminder($this->db);
2624
2625
        dol_syslog(__METHOD__ . " start", LOG_INFO);
2626
2627
        $this->db->begin();
2628
2629
        //Select all action comm reminders
2630
        $sql = "SELECT rowid as id FROM " . MAIN_DB_PREFIX . "actioncomm_reminder";
2631
        $sql .= " WHERE typeremind = 'email'";
2632
        $sql .= " AND status = 0";  // 0=No yet sent, -1=Error. TODO Include reminder in error once we can count number of error, so we can try 5 times and not more on errors.
2633
        $sql .= " AND dateremind <= '" . $this->db->idate($now) . "'";
2634
        $sql .= " AND entity IN (" . getEntity('actioncomm') . ")";
2635
        $sql .= $this->db->order("dateremind", "ASC");
2636
        $resql = $this->db->query($sql);
2637
2638
        if ($resql) {
2639
            $formmail = new FormMail($this->db);
2640
            $to = null;  // Ensure 'to' is defined for static analysis
2641
2642
            while ($obj = $this->db->fetch_object($resql)) {
2643
                $res = $actionCommReminder->fetch($obj->id);
2644
                if ($res < 0) {
2645
                    $error++;
2646
                    $errorsMsg[] = "Failed to load invoice ActionComm Reminder";
2647
                }
2648
2649
                if (!$error) {
2650
                    //Select email template
2651
                    $arraymessage = $formmail->getEMailTemplate($this->db, 'actioncomm_send', $user, $langs, (!empty($actionCommReminder->fk_email_template)) ? $actionCommReminder->fk_email_template : -1, 1);
2652
2653
                    // Load event
2654
                    $res = $this->fetch($actionCommReminder->fk_actioncomm);
2655
                    if ($res > 0) {
2656
                        // PREPARE EMAIL
2657
                        $errormesg = '';
2658
2659
                        // Make substitution in email content
2660
                        $substitutionarray = getCommonSubstitutionArray($langs, 0, '', $this);
2661
2662
                        complete_substitutions_array($substitutionarray, $langs, $this);
2663
2664
                        // Content
2665
                        $sendContent = make_substitutions($langs->trans($arraymessage->content), $substitutionarray);
2666
2667
                        //Topic
2668
                        $sendTopic = (!empty($arraymessage->topic)) ? $arraymessage->topic : html_entity_decode($langs->transnoentities('EventReminder'));
2669
2670
                        // Recipient
2671
                        $recipient = new User($this->db);
2672
                        $res = $recipient->fetch($actionCommReminder->fk_user);
2673
                        if ($res > 0) {
2674
                            if (!empty($recipient->email)) {
2675
                                $to = $recipient->email;
2676
                            } else {
2677
                                $errormesg = "Failed to send remind to user id=" . $actionCommReminder->fk_user . ". No email defined for user.";
2678
                                $error++;
2679
                            }
2680
                        } else {
2681
                            $errormesg = "Failed to load recipient with user id=" . $actionCommReminder->fk_user;
2682
                            $error++;
2683
                        }
2684
2685
                        // Sender
2686
                        $from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
2687
                        if (empty($from)) {
2688
                            $errormesg = "Failed to get sender into global setup MAIN_MAIL_EMAIL_FROM";
2689
                            $error++;
2690
                        }
2691
2692
                        if (!$error) {
2693
                            // Errors Recipient
2694
                            $errors_to = getDolGlobalString('MAIN_MAIL_ERRORS_TO');
2695
2696
                            // Mail Creation
2697
                            $cMailFile = new CMailFile($sendTopic, $to, $from, $sendContent, array(), array(), array(), '', "", 0, 1, $errors_to, '', '', '', '', '');
2698
2699
                            // Sending Mail
2700
                            if ($cMailFile->sendfile()) {
2701
                                $nbMailSend++;
2702
                            } else {
2703
                                $errormesg = 'Failed to send email to: ' . $to . ' ' . $cMailFile->error . implode(',', $cMailFile->errors);
2704
                                $error++;
2705
                            }
2706
                        }
2707
2708
                        if (!$error) {
2709
                            $actionCommReminder->status = $actionCommReminder::STATUS_DONE;
2710
2711
                            $res = $actionCommReminder->update($user);
2712
                            if ($res < 0) {
2713
                                $errorsMsg[] = "Failed to update status to done of ActionComm Reminder";
2714
                                $error++;
2715
                                break; // This is to avoid to have this error on all the selected email. If we fails here for one record, it may fails for others. We must solve first.
2716
                            }
2717
                        } else {
2718
                            $actionCommReminder->status = $actionCommReminder::STATUS_ERROR;
2719
                            $actionCommReminder->lasterror = dol_trunc($errormesg, 128, 'right', 'UTF-8', 1);
2720
2721
                            $res = $actionCommReminder->update($user);
2722
                            if ($res < 0) {
2723
                                $errorsMsg[] = "Failed to update status to error of ActionComm Reminder";
2724
                                $error++;
2725
                                break; // This is to avoid to have this error on all the selected email. If we fails here for one record, it may fails for others. We must solve first.
2726
                            } else {
2727
                                $errorsMsg[] = $errormesg;
2728
                            }
2729
                        }
2730
                    } else {
2731
                        $errorsMsg[] = 'Failed to fetch record actioncomm with ID = ' . $actionCommReminder->fk_actioncomm;
2732
                        $error++;
2733
                    }
2734
                }
2735
            }
2736
        } else {
2737
            $error++;
2738
        }
2739
2740
        if (!$error) {
2741
            // Delete also very old past events (we do not keep more than 1 month record in past)
2742
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "actioncomm_reminder";
2743
            $sql .= " WHERE dateremind < '" . $this->db->idate($now - (3600 * 24 * 32)) . "'";
2744
            $sql .= " AND status = " . ((int) $actionCommReminder::STATUS_DONE);
2745
            $resql = $this->db->query($sql);
2746
2747
            if (!$resql) {
2748
                $errorsMsg[] = 'Failed to delete old reminders';
2749
                //$error++;     // If this fails, we must not rollback other SQL requests already done. Never mind.
2750
            }
2751
        }
2752
2753
        if (!$error) {
2754
            $this->output = 'Nb of emails sent : ' . $nbMailSend;
2755
            $this->db->commit();
2756
2757
            dol_syslog(__METHOD__ . " end - " . $this->output, LOG_INFO);
2758
2759
            return 0;
2760
        } else {
2761
            $this->db->commit(); // We commit also on error, to have the error message recorded.
2762
            $this->error = 'Nb of emails sent : ' . $nbMailSend . ', ' . (!empty($errorsMsg) ? implode(', ', $errorsMsg) : $error);
2763
2764
            dol_syslog(__METHOD__ . " end - " . $this->error, LOG_INFO);
2765
2766
            return $error;
2767
        }
2768
    }
2769
2770
    /**
2771
     * Update the percent value of a event with the given id
2772
     *
2773
     * @param int           $id         The id of the event
2774
     * @param int<0,100>    $percent    The new percent value for the event
2775
     * @param int           $usermodid  The user who modified the percent
2776
     * @return int<-1,1>                1 when update of the event was successful, otherwise -1
2777
     */
2778
    public function updatePercent($id, $percent, $usermodid = 0)
2779
    {
2780
        $this->db->begin();
2781
2782
        $sql = "UPDATE " . MAIN_DB_PREFIX . "actioncomm ";
2783
        $sql .= " SET percent = " . (int) $percent;
2784
        if ($usermodid > 0) {
2785
            $sql .= ", fk_user_mod = " . $usermodid;
2786
        }
2787
        $sql .= " WHERE id = " . ((int) $id);
2788
2789
        if ($this->db->query($sql)) {
2790
            $this->db->commit();
2791
            return 1;
2792
        } else {
2793
            $this->db->rollback();
2794
            $this->error = $this->db->lasterror();
2795
            return -1;
2796
        }
2797
    }
2798
}
2799