Passed
Pull Request — dev (#6)
by Rafael
79:24 queued 24:08
created

Fichinter::delete()   F

Complexity

Conditions 23
Paths > 20000

Size

Total Lines 113
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 67
nc 21871
nop 2
dl 0
loc 113
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2002-2003  Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2004-2014  Laurent Destailleur         <[email protected]>
5
 * Copyright (C) 2005-2012  Regis Houssin               <[email protected]>
6
 * Copyright (C) 2011-2020  Juanjo Menent               <[email protected]>
7
 * Copyright (C) 2015       Marcos García               <[email protected]>
8
 * Copyright (C) 2015-2020  Charlene Benke              <[email protected]>
9
 * Copyright (C) 2018       Nicolas ZABOURI	            <[email protected]>
10
 * Copyright (C) 2018-2024  Frédéric France             <[email protected]>
11
 * Copyright (C) 2023-2024  William Mead                <[email protected]>
12
 * Copyright (C) 2024		MDW							<[email protected]>
13
 * Copyright (C) 2024       Rafael San José             <[email protected]>
14
 *
15
 * This program is free software; you can redistribute it and/or modify
16
 * it under the terms of the GNU General Public License as published by
17
 * the Free Software Foundation; either version 3 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU General Public License
26
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
27
 */
28
29
namespace Dolibarr\Code\FichInter\Classes;
30
31
use Dolibarr\Core\Base\CommonObject;
32
33
/**
34
 *  \file       htdocs/fichinter/class/fichinter.class.php
35
 *  \ingroup    fichinter
36
 *  \brief      File for class to manage interventions
37
 */
38
39
/**
40
 *  Class to manage interventions
41
 */
42
class Fichinter extends CommonObject
43
{
44
    public $fields = array(
45
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
46
        'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 'isModEnabled("societe")', 'visible' => -1, 'notnull' => 1, 'position' => 15),
47
        'fk_projet' => array('type' => 'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label' => 'Fk projet', 'enabled' => 'isModEnabled("project")', 'visible' => -1, 'position' => 20),
48
        'fk_contrat' => array('type' => 'integer', 'label' => 'Fk contrat', 'enabled' => '$conf->contrat->enabled', 'visible' => -1, 'position' => 25),
49
        'ref' => array('type' => 'varchar(30)', 'label' => 'Ref', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'showoncombobox' => 1, 'position' => 30),
50
        'ref_ext' => array('type' => 'varchar(255)', 'label' => 'Ref ext', 'enabled' => 1, 'visible' => 0, 'position' => 35),
51
        'ref_client' => array('type' => 'varchar(255)', 'label' => 'RefCustomer', 'enabled' => 1, 'visible' => -1, 'position' => 36),
52
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 40, 'index' => 1),
53
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 45),
54
        'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 50),
55
        'date_valid' => array('type' => 'datetime', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -1, 'position' => 55),
56
        'datei' => array('type' => 'date', 'label' => 'Datei', 'enabled' => 1, 'visible' => -1, 'position' => 60),
57
        'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'position' => 65),
58
        'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 70),
59
        'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 75),
60
        'dateo' => array('type' => 'date', 'label' => 'Dateo', 'enabled' => 1, 'visible' => -1, 'position' => 85),
61
        'datee' => array('type' => 'date', 'label' => 'Datee', 'enabled' => 1, 'visible' => -1, 'position' => 90),
62
        'datet' => array('type' => 'date', 'label' => 'Datet', 'enabled' => 1, 'visible' => -1, 'position' => 95),
63
        'duree' => array('type' => 'double', 'label' => 'Duree', 'enabled' => 1, 'visible' => -1, 'position' => 100),
64
        'signed_status' => array('type' => 'smallint(6)', 'label' => 'SignedStatus', 'enabled' => 1, 'visible' => -1, 'position' => 101, 'arrayofkeyval' => array(0 => 'NoSignature', 1 => 'SignedSender', 2 => 'SignedReceiver', 9 => 'SignedAll')),
65
        'description' => array('type' => 'html', 'label' => 'Description', 'enabled' => 1, 'visible' => -1, 'position' => 105, 'showoncombobox' => 2),
66
        'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 110),
67
        'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 115),
68
        'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 120),
69
        'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'Last main doc', 'enabled' => 1, 'visible' => -1, 'position' => 125),
70
        'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 130),
71
        'extraparams' => array('type' => 'varchar(255)', 'label' => 'Extraparams', 'enabled' => 1, 'visible' => -1, 'position' => 135),
72
        'fk_statut' => array('type' => 'integer', 'label' => 'Fk statut', 'enabled' => 1, 'visible' => -1, 'position' => 500),
73
    );
74
75
    /**
76
     * @var string ID to identify managed object
77
     */
78
    public $element = 'fichinter';
79
80
    /**
81
     * @var string Name of table without prefix where object is stored
82
     */
83
    public $table_element = 'fichinter';
84
85
    /**
86
     * @var string Field with ID of parent key if this field has a parent
87
     */
88
    public $fk_element = 'fk_fichinter';
89
90
    /**
91
     * @var string    Name of subtable line
92
     */
93
    public $table_element_line = 'fichinterdet';
94
95
    /**
96
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
97
     */
98
    public $picto = 'intervention';
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    protected $table_ref_field = 'ref';
104
105
    /**
106
     * @var int Thirdparty Id
107
     */
108
    public $socid;
109
110
    public $author;
111
112
    /**
113
     * Date creation record (datec)
114
     *
115
     * @var integer
116
     */
117
    public $datec;
118
119
    public $datev;
120
    public $dateo;
121
    public $datee;
122
    public $datet;
123
124
    /**
125
     * Date modification record (tms)
126
     *
127
     * @var integer
128
     */
129
    public $datem;
130
131
    /**
132
     * @var int duration
133
     */
134
    public $duration;
135
136
    /**
137
     * @var int status
138
     */
139
    public $statut = 0; // 0=draft, 1=validated, 2=invoiced, 3=Terminate
140
141
    /**
142
     * Signed Status of the intervention (0=NoSignature, 1=SignedBySender, 2=SignedByReceiver, 9=SignedByAll)
143
     * @var int
144
     */
145
    public $signed_status = 0;
146
147
    /**
148
     * @var string description
149
     */
150
    public $description;
151
152
    /**
153
     * @var int Contract ID
154
     */
155
    public $fk_contrat = 0;
156
157
    /**
158
     * @var int Project ID
159
     */
160
    public $fk_project = 0;
161
162
    /**
163
     * Customer Ref
164
     * @var string
165
     */
166
    public $ref_client;
167
168
    /**
169
     * @var array extraparams
170
     */
171
    public $extraparams = array();
172
173
    /**
174
     * @var FichinterLigne[] lines
175
     */
176
    public $lines = array();
177
178
    /**
179
     * Draft status
180
     */
181
    const STATUS_DRAFT = 0;
182
183
    /**
184
     * Validated status
185
     */
186
    const STATUS_VALIDATED = 1;
187
188
    /**
189
     * Billed
190
     */
191
    const STATUS_BILLED = 2;
192
193
    /**
194
     * Closed
195
     */
196
    const STATUS_CLOSED = 3;
197
198
199
    /**
200
     * No signature
201
     */
202
    const STATUS_NO_SIGNATURE    = 0;
203
204
    /**
205
     * Signed by sender
206
     */
207
    const STATUS_SIGNED_SENDER   = 1;
208
209
    /**
210
     * Signed by receiver
211
     */
212
    const STATUS_SIGNED_RECEIVER = 2;
213
214
    /**
215
     * Signed by all
216
     */
217
    const STATUS_SIGNED_ALL      = 9; // To handle future kind of signature (ex: tripartite contract)
218
219
220
    /**
221
     * Date delivery
222
     * @var string|int      Delivery int
223
     */
224
    public $date_delivery;
225
226
    /**
227
     * Author Id
228
     * @var int
229
     */
230
    public $user_author_id;
231
232
233
    /**
234
     *  Constructor
235
     *
236
     *  @param  DoliDB  $db     Database handler
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\FichInter\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
237
     */
238
    public function __construct($db)
239
    {
240
        $this->db = $db;
241
    }
242
243
    /**
244
     *  Load indicators into this->nb for board
245
     *
246
     *  @return     int         Return integer <0 if KO, >0 if OK
247
     */
248
    public function loadStateBoard()
249
    {
250
        global $user;
251
252
        $this->nb = array();
253
        $clause = "WHERE";
254
255
        $sql = "SELECT count(fi.rowid) as nb";
256
        $sql .= " FROM " . MAIN_DB_PREFIX . "fichinter as fi";
257
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON fi.fk_soc = s.rowid";
258
        if (!$user->hasRight('societe', 'client', 'voir')) {
259
            $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON s.rowid = sc.fk_soc";
260
            $sql .= " WHERE sc.fk_user = " . ((int) $user->id);
261
            $clause = "AND";
262
        }
263
        $sql .= " " . $clause . " fi.entity IN (" . getEntity('intervention') . ")";
264
265
        $resql = $this->db->query($sql);
266
        if ($resql) {
267
            while ($obj = $this->db->fetch_object($resql)) {
268
                $this->nb["interventions"] = $obj->nb;
269
            }
270
            $this->db->free($resql);
271
            return 1;
272
        } else {
273
            dol_print_error($this->db);
274
            $this->error = $this->db->error();
275
            return -1;
276
        }
277
    }
278
279
    /**
280
     *  Create an intervention into data base
281
     *
282
     *  @param      User    $user       Object user that make creation
283
     *  @param      int     $notrigger  Disable all triggers
284
     *  @return     int     Return integer <0 if KO, >0 if OK
285
     */
286
    public function create($user, $notrigger = 0)
287
    {
288
        global $conf, $langs;
289
290
        $error = 0;
291
292
        dol_syslog(get_class($this) . "::create ref=" . $this->ref);
293
294
        // Check parameters
295
        if (!empty($this->ref)) {   // We check that ref is not already used
296
            $result = self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
297
            if ($result > 0) {
298
                $this->error = 'ErrorRefAlreadyExists';
299
                dol_syslog(get_class($this) . "::create " . $this->error, LOG_WARNING);
300
                $this->db->rollback();
301
                return -1;
302
            }
303
        }
304
        if (!is_numeric($this->duration)) {
305
            $this->duration = 0;
306
        }
307
        if (isset($this->ref_client)) {
308
            $this->ref_client = trim($this->ref_client);
309
        }
310
311
        if ($this->socid <= 0) {
312
            $this->error = 'ErrorFicheinterCompanyDoesNotExist';
313
            dol_syslog(get_class($this) . "::create " . $this->error, LOG_ERR);
314
            return -1;
315
        }
316
317
        $soc = new Societe($this->db);
318
        $result = $soc->fetch($this->socid);
319
320
        $now = dol_now();
321
322
        $this->db->begin();
323
324
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "fichinter (";
325
        $sql .= "fk_soc";
326
        $sql .= ", datec";
327
        $sql .= ", ref";
328
        $sql .= ", ref_client";
329
        $sql .= ", entity";
330
        $sql .= ", fk_user_author";
331
        $sql .= ", fk_user_modif";
332
        $sql .= ", description";
333
        $sql .= ", model_pdf";
334
        $sql .= ", fk_projet";
335
        $sql .= ", fk_contrat";
336
        $sql .= ", fk_statut";
337
        $sql .= ", note_private";
338
        $sql .= ", note_public";
339
        $sql .= ") ";
340
        $sql .= " VALUES (";
341
        $sql .= $this->socid;
342
        $sql .= ", '" . $this->db->idate($now) . "'";
343
        $sql .= ", '" . $this->db->escape($this->ref) . "'";
344
        $sql .= ", " . ($this->ref_client ? "'" . $this->db->escape($this->ref_client) . "'" : "null");
345
        $sql .= ", " . ((int) $conf->entity);
346
        $sql .= ", " . ((int) $user->id);
347
        $sql .= ", " . ((int) $user->id);
348
        $sql .= ", " . ($this->description ? "'" . $this->db->escape($this->description) . "'" : "null");
349
        $sql .= ", '" . $this->db->escape($this->model_pdf) . "'";
350
        $sql .= ", " . ($this->fk_project ? ((int) $this->fk_project) : 0);
351
        $sql .= ", " . ($this->fk_contrat ? ((int) $this->fk_contrat) : 0);
352
        $sql .= ", " . ((int) $this->statut);
353
        $sql .= ", " . ($this->note_private ? "'" . $this->db->escape($this->note_private) . "'" : "null");
354
        $sql .= ", " . ($this->note_public ? "'" . $this->db->escape($this->note_public) . "'" : "null");
355
        $sql .= ")";
356
357
        dol_syslog(get_class($this) . "::create", LOG_DEBUG);
358
        $result = $this->db->query($sql);
359
        if ($result) {
360
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "fichinter");
361
362
            if ($this->id) {
363
                $this->ref = '(PROV' . $this->id . ')';
364
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "fichinter SET ref='" . $this->db->escape($this->ref) . "' WHERE rowid=" . ((int) $this->id);
365
366
                dol_syslog(get_class($this) . "::create", LOG_DEBUG);
367
                $resql = $this->db->query($sql);
368
                if (!$resql) {
369
                    $error++;
370
                }
371
            }
372
373
            if (!$error) {
374
                $result = $this->insertExtraFields();
375
                if ($result < 0) {
376
                    $error++;
377
                }
378
            }
379
380
            // Add linked object
381
            if (!$error && $this->origin && $this->origin_id) {
382
                $ret = $this->add_object_linked();
383
                if (!$ret) {
384
                    dol_print_error($this->db);
385
                }
386
            }
387
388
389
            if (!$error && !$notrigger) {
390
                // Call trigger
391
                $result = $this->call_trigger('FICHINTER_CREATE', $user);
392
                if ($result < 0) {
393
                    $error++;
394
                }
395
                // End call triggers
396
            }
397
398
            if (!$error) {
399
                $this->db->commit();
400
                return $this->id;
401
            } else {
402
                $this->db->rollback();
403
                $this->error = implode(',', $this->errors);
404
                dol_syslog(get_class($this) . "::create " . $this->error, LOG_ERR);
405
                return -1;
406
            }
407
        } else {
408
            $this->error = $this->db->error();
409
            $this->db->rollback();
410
            return -1;
411
        }
412
    }
413
414
    /**
415
     *  Update an intervention
416
     *
417
     *  @param      User    $user       Object user that make creation
418
     *  @param      int     $notrigger  Disable all triggers
419
     *  @return     int     Return integer <0 if KO, >0 if OK
420
     */
421
    public function update($user, $notrigger = 0)
422
    {
423
        global $conf;
424
425
        if (!is_numeric($this->duration)) {
426
            $this->duration = 0;
427
        }
428
        if (!dol_strlen($this->fk_project)) {
429
            $this->fk_project = 0;
430
        }
431
        if (isset($this->ref_client)) {
432
            $this->ref_client = trim($this->ref_client);
433
        }
434
435
        $error = 0;
436
437
        $this->db->begin();
438
439
        $sql = "UPDATE " . MAIN_DB_PREFIX . "fichinter SET ";
440
        $sql .= "description  = '" . $this->db->escape($this->description) . "'";
441
        $sql .= ", duree = " . ((int) $this->duration);
442
        $sql .= ", ref_client = " . ($this->ref_client ? "'" . $this->db->escape($this->ref_client) . "'" : "null");
443
        $sql .= ", fk_projet = " . ((int) $this->fk_project);
444
        $sql .= ", note_private = " . ($this->note_private ? "'" . $this->db->escape($this->note_private) . "'" : "null");
445
        $sql .= ", note_public = " . ($this->note_public ? "'" . $this->db->escape($this->note_public) . "'" : "null");
446
        $sql .= ", fk_user_modif = " . ((int) $user->id);
447
        $sql .= " WHERE rowid = " . ((int) $this->id);
448
449
        dol_syslog(get_class($this) . "::update", LOG_DEBUG);
450
        if ($this->db->query($sql)) {
451
            if (!$error) {
452
                $result = $this->insertExtraFields();
453
                if ($result < 0) {
454
                    $error++;
455
                }
456
            }
457
458
            if (!$error && !$notrigger) {
459
                // Call trigger
460
                $result = $this->call_trigger('FICHINTER_MODIFY', $user);
461
                if ($result < 0) {
462
                    $error++;
463
                    $this->db->rollback();
464
                    return -1;
465
                }
466
                // End call triggers
467
            }
468
469
            $this->db->commit();
470
            return 1;
471
        } else {
472
            $this->error = $this->db->error();
473
            $this->db->rollback();
474
            return -1;
475
        }
476
    }
477
478
    /**
479
     *  Fetch a intervention
480
     *
481
     *  @param      int     $rowid      Id of intervention
482
     *  @param      string  $ref        Ref of intervention
483
     *  @return     int                 Return integer <0 if KO, >0 if OK
484
     */
485
    public function fetch($rowid, $ref = '')
486
    {
487
        $sql = "SELECT f.rowid, f.ref, f.ref_client, f.description, f.fk_soc, f.fk_statut as status,";
488
        $sql .= " f.datec, f.dateo, f.datee, f.datet, f.fk_user_author,";
489
        $sql .= " f.date_valid as datev,";
490
        $sql .= " f.tms as datem,";
491
        $sql .= " f.duree, f.fk_projet as fk_project, f.note_public, f.note_private, f.model_pdf, f.last_main_doc, f.extraparams, fk_contrat, f.entity as entity";
492
        $sql .= " FROM " . MAIN_DB_PREFIX . "fichinter as f";
493
        if ($ref) {
494
            $sql .= " WHERE f.entity IN (" . getEntity('intervention') . ")";
495
            $sql .= " AND f.ref = '" . $this->db->escape($ref) . "'";
496
        } else {
497
            $sql .= " WHERE f.rowid = " . ((int) $rowid);
498
        }
499
500
        dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
501
        $resql = $this->db->query($sql);
502
        if ($resql) {
503
            if ($this->db->num_rows($resql)) {
504
                $obj = $this->db->fetch_object($resql);
505
506
                $this->id           = $obj->rowid;
507
                $this->ref          = $obj->ref;
508
                $this->ref_client   = $obj->ref_client;
509
                $this->description  = $obj->description;
510
                $this->socid        = $obj->fk_soc;
511
                $this->status       = $obj->status;
512
                $this->statut       = $obj->status; // deprecated
513
                $this->duration     = $obj->duree;
514
                $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...
515
                $this->dateo        = $this->db->jdate($obj->dateo);
516
                $this->datee        = $this->db->jdate($obj->datee);
517
                $this->datet        = $this->db->jdate($obj->datet);
518
                $this->datev        = $this->db->jdate($obj->datev);
519
                $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...
520
                $this->fk_project   = $obj->fk_project;
521
                $this->note_public  = $obj->note_public;
522
                $this->note_private = $obj->note_private;
523
                $this->model_pdf    = $obj->model_pdf;
524
                $this->fk_contrat = $obj->fk_contrat;
525
                $this->entity = $obj->entity;
526
527
                $this->user_creation_id = $obj->fk_user_author;
528
529
                $this->extraparams = (array) json_decode($obj->extraparams, true);
530
531
                $this->last_main_doc = $obj->last_main_doc;
532
533
                // Retrieve extrafields
534
                $this->fetch_optionals();
535
536
                /*
537
                 * Lines
538
                 */
539
                $result = $this->fetch_lines();
540
                if ($result < 0) {
541
                    return -3;
542
                }
543
                $this->db->free($resql);
544
                return 1;
545
            }
546
547
            return 0;
548
        } else {
549
            $this->error = $this->db->lasterror();
550
            return -1;
551
        }
552
    }
553
554
    /**
555
     *  Set status to draft
556
     *
557
     *  @param      User    $user   User that set draft
558
     *  @return     int             Return integer <0 if KO, >0 if OK
559
     */
560
    public function setDraft($user)
561
    {
562
        $error = 0;
563
564
        // Protection
565
        if ($this->statut <= self::STATUS_DRAFT) {
566
            return 0;
567
        }
568
569
        dol_syslog(get_class($this) . "::setDraft", LOG_DEBUG);
570
571
        $this->oldcopy = dol_clone($this, 2);
572
573
        $this->db->begin();
574
575
        $sql = "UPDATE " . MAIN_DB_PREFIX . "fichinter";
576
        $sql .= " SET fk_statut = " . self::STATUS_DRAFT;
577
        $sql .= " WHERE rowid = " . ((int) $this->id);
578
579
        $resql = $this->db->query($sql);
580
        if ($resql) {
581
            if (!$error) {
582
                // Call trigger
583
                $result = $this->call_trigger('FICHINTER_UNVALIDATE', $user);
584
                if ($result < 0) {
585
                    $error++;
586
                }
587
            }
588
589
            if (!$error) {
590
                $this->statut = self::STATUS_DRAFT;
591
                $this->db->commit();
592
                return 1;
593
            } else {
594
                $this->db->rollback();
595
                return -1;
596
            }
597
        } else {
598
            $this->db->rollback();
599
            $this->error = $this->db->lasterror();
600
            return -1;
601
        }
602
    }
603
604
    /**
605
     *  Validate a intervention
606
     *
607
     *  @param      User        $user       User that validate
608
     *  @param      int         $notrigger  1=Does not execute triggers, 0= execute triggers
609
     *  @return     int                     Return integer <0 if KO, >0 if OK
610
     */
611
    public function setValid($user, $notrigger = 0)
612
    {
613
        global $conf;
614
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
615
616
        $error = 0;
617
618
        if ($this->status != self::STATUS_VALIDATED) {
619
            $this->db->begin();
620
621
            $now = dol_now();
622
623
            // Define new ref
624
            if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
625
                $num = $this->getNextNumRef($this->thirdparty);
626
            } else {
627
                $num = $this->ref;
628
            }
629
            $this->newref = dol_sanitizeFileName($num);
630
631
            $sql = "UPDATE " . MAIN_DB_PREFIX . "fichinter";
632
            $sql .= " SET fk_statut = 1";
633
            $sql .= ", ref = '" . $this->db->escape($num) . "'";
634
            $sql .= ", date_valid = '" . $this->db->idate($now) . "'";
635
            $sql .= ", fk_user_valid = " . ($user->id > 0 ? (int) $user->id : "null");
636
            $sql .= " WHERE rowid = " . ((int) $this->id);
637
            $sql .= " AND entity = " . ((int) $this->entity);
638
639
            $sql .= " AND fk_statut = 0";
640
641
            dol_syslog(get_class($this) . "::setValid", LOG_DEBUG);
642
            $resql = $this->db->query($sql);
643
            if (!$resql) {
644
                dol_print_error($this->db);
645
                $error++;
646
            }
647
648
            if (!$error && !$notrigger) {
649
                // Call trigger
650
                $result = $this->call_trigger('FICHINTER_VALIDATE', $user);
651
                if ($result < 0) {
652
                    $error++;
653
                }
654
                // End call triggers
655
            }
656
657
            if (!$error) {
658
                $this->oldref = $this->ref;
659
660
                // Rename directory if dir was a temporary ref
661
                if (preg_match('/^[\(]?PROV/i', $this->ref)) {
662
                    require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
663
664
                    // Now we rename also files into index
665
                    $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'ficheinter/" . $this->db->escape($this->newref) . "'";
666
                    $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'ficheinter/" . $this->db->escape($this->ref) . "' and entity = " . ((int) $this->entity);
667
                    $resql = $this->db->query($sql);
668
                    if (!$resql) {
669
                        $error++;
670
                        $this->error = $this->db->lasterror();
671
                    }
672
                    $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'ficheinter/" . $this->db->escape($this->newref) . "'";
673
                    $sql .= " WHERE filepath = 'ficheinter/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
674
                    $resql = $this->db->query($sql);
675
                    if (!$resql) {
676
                        $error++;
677
                        $this->error = $this->db->lasterror();
678
                    }
679
680
                    // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
681
                    $oldref = dol_sanitizeFileName($this->ref);
682
                    $newref = dol_sanitizeFileName($num);
683
                    $dirsource = $conf->ficheinter->dir_output . '/' . $oldref;
684
                    $dirdest = $conf->ficheinter->dir_output . '/' . $newref;
685
                    if (!$error && file_exists($dirsource)) {
686
                        dol_syslog(get_class($this) . "::setValid rename dir " . $dirsource . " into " . $dirdest);
687
688
                        if (@rename($dirsource, $dirdest)) {
689
                            dol_syslog("Rename ok");
690
                            // Rename docs starting with $oldref with $newref
691
                            $listoffiles = dol_dir_list($conf->ficheinter->dir_output . '/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/'));
692
                            foreach ($listoffiles as $fileentry) {
693
                                $dirsource = $fileentry['name'];
694
                                $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource);
695
                                $dirsource = $fileentry['path'] . '/' . $dirsource;
696
                                $dirdest = $fileentry['path'] . '/' . $dirdest;
697
                                @rename($dirsource, $dirdest);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

697
                                /** @scrutinizer ignore-unhandled */ @rename($dirsource, $dirdest);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
698
                            }
699
                        }
700
                    }
701
                }
702
            }
703
704
            // Set new ref and define current statut
705
            if (!$error) {
706
                $this->ref = $num;
707
                $this->status = self::STATUS_VALIDATED;
708
                $this->statut = self::STATUS_VALIDATED; // deprecated
709
                $this->date_validation = $now;
710
                $this->db->commit();
711
                return 1;
712
            } else {
713
                $this->db->rollback();
714
                dol_syslog(get_class($this) . "::setValid " . $this->error, LOG_ERR);
715
                return -1;
716
            }
717
        }
718
719
        return 0;
720
    }
721
722
    /**
723
     *  Close intervention
724
     *
725
     *  @param      User    $user       Object user that close
726
     *  @param      int     $notrigger  1=Does not execute triggers, 0=Execute triggers
727
     *  @return     int                 Return integer <0 if KO, >0 if OK
728
     */
729
    public function setClose($user, $notrigger = 0)
730
    {
731
        global $conf;
732
733
        $error = 0;
734
735
        if ($this->statut == self::STATUS_CLOSED) {
736
            return 0;
737
        } else {
738
            $this->db->begin();
739
740
            $now = dol_now();
741
742
            $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element;
743
            $sql .= ' SET fk_statut = ' . self::STATUS_CLOSED . ',';
744
            $sql .= " datet = '" . $this->db->idate($now) . "',";
745
            $sql .= " fk_user_modif = " . ((int) $user->id);
746
            $sql .= " WHERE rowid = " . ((int) $this->id);
747
            $sql .= " AND fk_statut > " . self::STATUS_DRAFT;
748
            $sql .= " AND entity = " . ((int) $conf->entity);
749
750
            if ($this->db->query($sql)) {
751
                if (!$notrigger) {
752
                    // Call trigger
753
                    $result = $this->call_trigger('FICHINTER_CLOSE', $user);
754
                    if ($result < 0) {
755
                        $error++;
756
                    }
757
                    // End call triggers
758
                }
759
760
                if (!$error) {
761
                    $this->statut = self::STATUS_CLOSED;
762
                    $this->db->commit();
763
                    return 1;
764
                } else {
765
                    $this->db->rollback();
766
                    return -1;
767
                }
768
            } else {
769
                $this->error = $this->db->lasterror();
770
                $this->db->rollback();
771
                return -1;
772
            }
773
        }
774
    }
775
776
    /**
777
     *  Returns amount based on user thm
778
     *
779
     *  @return     float       Amount
780
     */
781
    public function getAmount()
782
    {
783
        $amount = 0;
784
785
        $this->author = new User($this->db);
786
        $this->author->fetch($this->user_creation_id);
787
788
        $thm = $this->author->thm;
789
790
        foreach ($this->lines as $line) {
791
            $amount += ($line->duration / 60 / 60 * (float) $thm);
792
        }
793
794
        return (float) price2num($amount, 'MT');
795
    }
796
797
798
    /**
799
     *  Create a document onto disk according to template module.
800
     *
801
     *  @param      string                  $modele         Force model to use ('' to not force)
802
     *  @param      Translate               $outputlangs    Object langs to use for output
803
     *  @param      int                     $hidedetails    Hide details of lines
804
     *  @param      int                     $hidedesc       Hide description
805
     *  @param      int                     $hideref        Hide ref
806
     *  @param   null|array  $moreparams     Array to provide more information
807
     *  @return     int                                     0 if KO, 1 if OK
808
     */
809
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
810
    {
811
        global $conf;
812
813
        $outputlangs->load("interventions");
814
815
        if (!dol_strlen($modele)) {
816
            $modele = 'soleil';
817
818
            if (!empty($this->model_pdf)) {
819
                $modele = $this->model_pdf;
820
            } elseif (getDolGlobalString('FICHEINTER_ADDON_PDF')) {
821
                $modele = getDolGlobalString('FICHEINTER_ADDON_PDF');
822
            }
823
        }
824
825
        $modelpath = "core/modules/fichinter/doc/";
826
827
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
828
    }
829
830
    /**
831
     *  Returns the label status
832
     *
833
     *  @param      int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
834
     *  @return     string              Label
835
     */
836
    public function getLibStatut($mode = 0)
837
    {
838
        return $this->LibStatut((isset($this->statut) ? $this->statut : $this->status), $mode);
839
    }
840
841
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
842
    /**
843
     *  Returns the label of a status
844
     *
845
     *  @param      int     $status     Id status
846
     *  @param      int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
847
     *  @return     string              Label
848
     */
849
    public function LibStatut($status, $mode = 0)
850
    {
851
		// phpcs:enable
852
        // Init/load array of translation of status
853
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
854
            global $langs;
855
            $langs->load("fichinter");
856
857
            $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
858
            $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
859
            $this->labelStatus[self::STATUS_BILLED] = $langs->transnoentitiesnoconv('StatusInterInvoiced');
860
            $this->labelStatus[self::STATUS_CLOSED] = $langs->transnoentitiesnoconv('Done');
861
            $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
862
            $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
863
            $this->labelStatusShort[self::STATUS_BILLED] = $langs->transnoentitiesnoconv('StatusInterInvoiced');
864
            $this->labelStatusShort[self::STATUS_CLOSED] = $langs->transnoentitiesnoconv('Done');
865
        }
866
867
        $statuscode = 'status' . $status;
868
        if ($status == self::STATUS_BILLED || $status == self::STATUS_CLOSED) {
869
            $statuscode = 'status6';
870
        }
871
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statuscode, $mode);
872
    }
873
874
    /**
875
     * getTooltipContentArray
876
     *
877
     * @param array $params ex option, infologin
878
     * @since v18
879
     * @return array
880
     */
881
    public function getTooltipContentArray($params)
882
    {
883
        global $conf, $langs;
884
885
        $langs->load('fichinter');
886
887
        $datas = [];
888
        $datas['picto'] = img_picto('', $this->picto) . ' <u class="paddingrightonly">' . $langs->trans("Intervention") . '</u>';
889
        if (isset($this->status)) {
890
            $datas['picto'] .= ' ' . $this->getLibStatut(5);
891
        }
892
        $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
893
894
        return $datas;
895
    }
896
897
    /**
898
     *  Return clicable name (with picto eventually)
899
     *
900
     *  @param      int     $withpicto                  0=_No picto, 1=Includes the picto in the linkn, 2=Picto only
901
     *  @param      string  $option                     Options
902
     *  @param      int     $notooltip                  1=Disable tooltip
903
     *  @param      int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
904
     *  @param      string  $morecss                    Add more css on link
905
     *  @return     string                              String with URL
906
     */
907
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $save_lastsearch_value = -1, $morecss = '')
908
    {
909
        global $conf, $langs, $hookmanager;
910
911
        if (!empty($conf->dol_no_mouse_hover)) {
912
            $notooltip = 1; // Force disable tooltips
913
        }
914
915
        $result = '';
916
        $params = [
917
            'id' => $this->id,
918
            'objecttype' => $this->element,
919
            'option' => $option,
920
        ];
921
        $classfortooltip = 'classfortooltip';
922
        $dataparams = '';
923
        if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
924
            $classfortooltip = 'classforajaxtooltip';
925
            $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"';
926
            $label = '';
927
        } else {
928
            $label = implode($this->getTooltipContentArray($params));
929
        }
930
931
        $url = constant('BASE_URL') . '/fichinter/card.php?id=' . $this->id;
932
933
        if ($option !== 'nolink') {
934
            // Add param to save lastsearch_values or not
935
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
936
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
937
                $add_save_lastsearch_values = 1;
938
            }
939
            if ($add_save_lastsearch_values) {
940
                $url .= '&save_lastsearch_values=1';
941
            }
942
        }
943
944
        $linkclose = '';
945
        if (empty($notooltip)) {
946
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
947
                $label = $langs->trans("ShowIntervention");
948
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
949
            }
950
            $linkclose .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"');
951
            $linkclose .= $dataparams . ' class="' . $classfortooltip . ($morecss ? ' ' . $morecss : '') . '"';
952
        } else {
953
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
954
        }
955
956
        if ($option == 'nolink' || empty($url)) {
957
            $linkstart = '<span';
958
        } else {
959
            $linkstart = '<a href="' . $url . '"';
960
        }
961
        $linkstart .= $linkclose . '>';
962
        if ($option == 'nolink' || empty($url)) {
963
            $linkend = '</span>';
964
        } else {
965
            $linkend = '</a>';
966
        }
967
968
        $result .= $linkstart;
969
        if ($withpicto) {
970
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . '"'), 0, 0, $notooltip ? 0 : 1);
971
        }
972
973
        if ($withpicto != 2) {
974
            $result .= $this->ref;
975
        }
976
977
        $result .= $linkend;
978
979
        global $action;
980
        $hookmanager->initHooks(array('interventiondao'));
981
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
982
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
983
        if ($reshook > 0) {
984
            $result = $hookmanager->resPrint;
985
        } else {
986
            $result .= $hookmanager->resPrint;
987
        }
988
989
        return $result;
990
    }
991
992
993
    /**
994
     *  Returns the next non used reference of intervention
995
     *  depending on the module numbering assets within FICHEINTER_ADDON
996
     *
997
     *  @param      Societe     $soc        Thirdparty object
998
     *  @return     string                  Free reference for intervention
999
     */
1000
    public function getNextNumRef($soc)
1001
    {
1002
        global $conf, $db, $langs;
1003
        $langs->load("interventions");
1004
1005
        if (getDolGlobalString('FICHEINTER_ADDON')) {
1006
            $mybool = false;
1007
1008
            $file = "mod_" . getDolGlobalString('FICHEINTER_ADDON') . ".php";
1009
            $classname = "mod_" . getDolGlobalString('FICHEINTER_ADDON');
1010
1011
            // Include file with class
1012
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1013
1014
            foreach ($dirmodels as $reldir) {
1015
                $dir = dol_buildpath($reldir . "core/modules/fichinter/");
1016
1017
                // Load file with numbering class (if found)
1018
                $mybool = ((bool) @include_once $dir . $file) || $mybool;
1019
            }
1020
1021
            if ($mybool === false) {
1022
                dol_print_error(null, "Failed to include file " . $file);
1023
                return '';
1024
            }
1025
1026
            $obj = new $classname();
1027
            $numref = "";
1028
            $numref = $obj->getNextValue($soc, $this);
1029
1030
            if ($numref != "") {
1031
                return $numref;
1032
            } else {
1033
                dol_print_error($db, "Fichinter::getNextNumRef " . $obj->error);
1034
                return "";
1035
            }
1036
        } else {
1037
            $langs->load("errors");
1038
            print $langs->trans("Error") . " " . $langs->trans("Error_FICHEINTER_ADDON_NotDefined");
1039
            return "";
1040
        }
1041
    }
1042
1043
    /**
1044
     *  Load information on object
1045
     *
1046
     *  @param  int     $id      Id of object
1047
     *  @return void
1048
     */
1049
    public function info($id)
1050
    {
1051
        $sql = "SELECT f.rowid,";
1052
        $sql .= " f.datec,";
1053
        $sql .= " f.tms as date_modification,";
1054
        $sql .= " f.date_valid as datev,";
1055
        $sql .= " f.fk_user_author,";
1056
        $sql .= " f.fk_user_modif as fk_user_modification,";
1057
        $sql .= " f.fk_user_valid";
1058
        $sql .= " FROM " . MAIN_DB_PREFIX . "fichinter as f";
1059
        $sql .= " WHERE f.rowid = " . ((int) $id);
1060
1061
        $resql = $this->db->query($sql);
1062
        if ($resql) {
1063
            if ($this->db->num_rows($resql)) {
1064
                $obj = $this->db->fetch_object($resql);
1065
1066
                $this->id                = $obj->rowid;
1067
1068
                $this->date_creation     = $this->db->jdate($obj->datec);
1069
                $this->date_modification = $this->db->jdate($obj->date_modification);
1070
                $this->date_validation   = $this->db->jdate($obj->datev);
1071
1072
                $this->user_creation_id = $obj->fk_user_author;
1073
                $this->user_validation_id = $obj->fk_user_valid;
1074
                $this->user_modification_id = $obj->fk_user_modification;
1075
            }
1076
            $this->db->free($resql);
1077
        } else {
1078
            dol_print_error($this->db);
1079
        }
1080
    }
1081
1082
    /**
1083
     *  Delete intervetnion
1084
     *
1085
     *  @param      User    $user           Object user who delete
1086
     *  @param      int     $notrigger      Disable trigger
1087
     *  @return     int                     Return integer <0 if KO, >0 if OK
1088
     */
1089
    public function delete(User $user, $notrigger = 0)
1090
    {
1091
        global $conf, $langs;
1092
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
1093
1094
        $error = 0;
1095
1096
        $this->db->begin();
1097
1098
        if (!$error && !$notrigger) {
1099
            // Call trigger
1100
            $result = $this->call_trigger('FICHINTER_DELETE', $user);
1101
            if ($result < 0) {
1102
                $error++;
1103
                $this->db->rollback();
1104
                return -1;
1105
            }
1106
            // End call triggers
1107
        }
1108
1109
        // Delete linked object
1110
        if (!$error) {
1111
            $res = $this->deleteObjectLinked();
1112
            if ($res < 0) {
1113
                $error++;
1114
            }
1115
        }
1116
1117
        // Delete linked contacts
1118
        if (!$error) {
1119
            $res = $this->delete_linked_contact();
1120
            if ($res < 0) {
1121
                $this->error = 'ErrorFailToDeleteLinkedContact';
1122
                $error++;
1123
            }
1124
        }
1125
1126
        if (!$error) {
1127
            $main = MAIN_DB_PREFIX . 'fichinterdet';
1128
            $ef = $main . "_extrafields";
1129
            $sql = "DELETE FROM $ef WHERE fk_object IN (SELECT rowid FROM $main WHERE fk_fichinter = " . ((int) $this->id) . ")";
1130
1131
            $resql = $this->db->query($sql);
1132
            if (!$resql) {
1133
                $error++;
1134
            }
1135
        }
1136
1137
        if (!$error) {
1138
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "fichinterdet";
1139
            $sql .= " WHERE fk_fichinter = " . ((int) $this->id);
1140
1141
            $resql = $this->db->query($sql);
1142
            if (!$resql) {
1143
                $error++;
1144
            }
1145
        }
1146
1147
        if (!$error) {
1148
            // Remove extrafields
1149
            $res = $this->deleteExtraFields();
1150
            if ($res < 0) {
1151
                $error++;
1152
            }
1153
        }
1154
1155
        if (!$error) {
1156
            // Delete object
1157
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "fichinter";
1158
            $sql .= " WHERE rowid = " . ((int) $this->id);
1159
1160
            dol_syslog("Fichinter::delete", LOG_DEBUG);
1161
            $resql = $this->db->query($sql);
1162
            if (!$resql) {
1163
                $error++;
1164
            }
1165
        }
1166
1167
        if (!$error) {
1168
            // Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
1169
            $this->deleteEcmFiles(0); // Deleting files physically is done later with the dol_delete_dir_recursive
1170
            $this->deleteEcmFiles(1); // Deleting files physically is done later with the dol_delete_dir_recursive
1171
1172
            // Remove directory with files
1173
            $fichinterref = dol_sanitizeFileName($this->ref);
1174
            if ($conf->ficheinter->dir_output) {
1175
                $dir = $conf->ficheinter->dir_output . "/" . $fichinterref;
1176
                $file = $conf->ficheinter->dir_output . "/" . $fichinterref . "/" . $fichinterref . ".pdf";
1177
                if (file_exists($file)) {
1178
                    dol_delete_preview($this);
1179
1180
                    if (!dol_delete_file($file, 0, 0, 0, $this)) { // For triggers
1181
                        $langs->load("errors");
1182
                        $this->error = $langs->trans("ErrorFailToDeleteFile", $file);
1183
                        return 0;
1184
                    }
1185
                }
1186
                if (file_exists($dir)) {
1187
                    if (!dol_delete_dir_recursive($dir)) {
1188
                        $langs->load("errors");
1189
                        $this->error = $langs->trans("ErrorFailToDeleteDir", $dir);
1190
                        return 0;
1191
                    }
1192
                }
1193
            }
1194
        }
1195
1196
        if (!$error) {
1197
            $this->db->commit();
1198
            return 1;
1199
        } else {
1200
            $this->db->rollback();
1201
            return -1;
1202
        }
1203
    }
1204
1205
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1206
    /**
1207
     *  Defines a delivery date of intervention
1208
     *
1209
     *  @param      User    $user               Object user who define
1210
     *  @param      integer $date_delivery      date of delivery
1211
     *  @return     int                         Return integer <0 if KO, >0 if OK
1212
     */
1213
    public function set_date_delivery($user, $date_delivery)
1214
    {
1215
		// phpcs:enable
1216
        if ($user->hasRight('ficheinter', 'creer')) {
1217
            $sql = "UPDATE " . MAIN_DB_PREFIX . "fichinter ";
1218
            $sql .= " SET datei = '" . $this->db->idate($date_delivery) . "'";
1219
            $sql .= " WHERE rowid = " . ((int) $this->id);
1220
            $sql .= " AND fk_statut = 0";
1221
1222
            if ($this->db->query($sql)) {
1223
                $this->date_delivery = $date_delivery;
1224
                return 1;
1225
            } else {
1226
                $this->error = $this->db->error();
1227
                dol_syslog("Fichinter::set_date_delivery Erreur SQL");
1228
                return -1;
1229
            }
1230
        }
1231
1232
        return 0;
1233
    }
1234
1235
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1236
    /**
1237
     *  Define the label of the intervention
1238
     *
1239
     *  @param      User    $user           Object user who modify
1240
     *  @param      string  $description    description
1241
     *  @return     int                     Return integer <0 if KO, >0 if OK
1242
     */
1243
    public function set_description($user, $description)
1244
    {
1245
		// phpcs:enable
1246
        if ($user->hasRight('ficheinter', 'creer')) {
1247
            $sql = "UPDATE " . MAIN_DB_PREFIX . "fichinter ";
1248
            $sql .= " SET description = '" . $this->db->escape($description) . "',";
1249
            $sql .= " fk_user_modif = " . $user->id;
1250
            $sql .= " WHERE rowid = " . ((int) $this->id);
1251
1252
            if ($this->db->query($sql)) {
1253
                $this->description = $description;
1254
                return 1;
1255
            } else {
1256
                $this->error = $this->db->error();
1257
                dol_syslog("Fichinter::set_description Erreur SQL");
1258
                return -1;
1259
            }
1260
        }
1261
1262
        return 0;
1263
    }
1264
1265
1266
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1267
    /**
1268
     *  Link intervention to a contract
1269
     *
1270
     *  @param      User    $user           Object user who modify
1271
     *  @param      int     $contractid     Description
1272
     *  @return     int                     Return integer <0 if KO, >0 if OK
1273
     */
1274
    public function set_contrat($user, $contractid)
1275
    {
1276
		// phpcs:enable
1277
        if ($user->hasRight('ficheinter', 'creer')) {
1278
            $sql = "UPDATE " . MAIN_DB_PREFIX . "fichinter ";
1279
            $sql .= " SET fk_contrat = " . ((int) $contractid);
1280
            $sql .= " WHERE rowid = " . ((int) $this->id);
1281
1282
            if ($this->db->query($sql)) {
1283
                $this->fk_contrat = $contractid;
1284
                return 1;
1285
            } else {
1286
                $this->error = $this->db->error();
1287
                return -1;
1288
            }
1289
        }
1290
1291
        return -2;
1292
    }
1293
1294
1295
1296
    /**
1297
     *  Load an object from its id and create a new one in database
1298
     *
1299
     *  @param      User    $user           User making the clone
1300
     *  @param      int     $socid          Id of thirdparty
1301
     *  @return     int                     New id of clone
1302
     */
1303
    public function createFromClone(User $user, $socid = 0)
1304
    {
1305
        global $hookmanager;
1306
1307
        $error = 0;
1308
1309
        $this->db->begin();
1310
1311
        // get extrafields so they will be clone
1312
        foreach ($this->lines as $line) {
1313
            $line->fetch_optionals();
1314
        }
1315
1316
        // Load source object
1317
        $objFrom = clone $this;
1318
1319
        // Change socid if needed
1320
        if (!empty($socid) && $socid != $this->socid) {
1321
            $objsoc = new Societe($this->db);
1322
1323
            if ($objsoc->fetch($socid) > 0) {
1324
                $this->socid = $objsoc->id;
1325
                //$this->cond_reglement_id  = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
1326
                //$this->mode_reglement_id  = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
1327
                $this->fk_project = 0;
1328
                $this->fk_delivery_address = 0;
1329
            }
1330
1331
            // TODO Change product price if multi-prices
1332
        }
1333
1334
        $this->id = 0;
1335
        $this->ref = '';
1336
        $this->status = self::STATUS_DRAFT;
1337
        $this->statut = self::STATUS_DRAFT; //  deprecated
1338
1339
        // Clear fields
1340
        $this->user_author_id     = $user->id;
1341
        $this->user_validation_id = 0;
1342
        $this->date_creation      = '';
1343
        $this->date_validation    = '';
1344
1345
        $this->ref_client         = '';
1346
1347
        // Create clone
1348
        $this->context['createfromclone'] = 'createfromclone';
1349
        $result = $this->create($user);
1350
        if ($result < 0) {
1351
            $error++;
1352
        }
1353
1354
        if (!$error) {
1355
            // Add lines because it is not included into create function
1356
            foreach ($this->lines as $line) {
1357
                $this->addline($user, $this->id, $line->desc, $line->datei, $line->duration, $line->array_options);
1358
            }
1359
1360
            // Hook of thirdparty module
1361
            if (is_object($hookmanager)) {
1362
                $parameters = array('objFrom' => $objFrom);
1363
                $action = '';
1364
                $reshook = $hookmanager->executeHooks('createFrom', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1365
                if ($reshook < 0) {
1366
                    $this->setErrorsFromObject($hookmanager);
1367
                    $error++;
1368
                }
1369
            }
1370
        }
1371
1372
        unset($this->context['createfromclone']);
1373
1374
        // End
1375
        if (!$error) {
1376
            $this->db->commit();
1377
            return $this->id;
1378
        } else {
1379
            $this->db->rollback();
1380
            return -1;
1381
        }
1382
    }
1383
1384
1385
    /**
1386
     *  Adding a line of intervention into data base
1387
     *
1388
     *  @param      user    $user                   User that do the action
1389
     *  @param      int     $fichinterid            Id of intervention
1390
     *  @param      string  $desc                   Line description
1391
     *  @param      integer $date_intervention      Intervention date
1392
     *  @param      int     $duration               Intervention duration
1393
     *  @param      array   $array_options          Array option
1394
     *  @return     int                             >0 if ok, <0 if ko
1395
     */
1396
    public function addline($user, $fichinterid, $desc, $date_intervention, $duration, $array_options = [])
1397
    {
1398
        dol_syslog(get_class($this) . "::addline $fichinterid, $desc, $date_intervention, $duration");
1399
1400
        if ($this->status == self::STATUS_DRAFT) {
1401
            $this->db->begin();
1402
1403
            // Insertion ligne
1404
            $line = new FichinterLigne($this->db);
1405
1406
            $line->fk_fichinter = $fichinterid;
1407
            $line->desc         = $desc;
1408
            $line->date         = $date_intervention;
1409
            $line->datei        = $date_intervention;   // For backward compatibility
1410
            $line->duration     = $duration;
1411
1412
            if (is_array($array_options) && count($array_options) > 0) {
1413
                $line->array_options = $array_options;
1414
            }
1415
1416
            $result = $line->insert($user);
1417
1418
            if ($result >= 0) {
1419
                $this->db->commit();
1420
                return 1;
1421
            } else {
1422
                $this->error = $this->db->error();
1423
                $this->db->rollback();
1424
                return -1;
1425
            }
1426
        }
1427
1428
        return 0;
1429
    }
1430
1431
1432
    /**
1433
     *  Initialise an instance with random values.
1434
     *  Used to build previews or test instances.
1435
     *  id must be 0 if object instance is a specimen.
1436
     *
1437
     *  @return int
1438
     */
1439
    public function initAsSpecimen()
1440
    {
1441
        global $langs;
1442
1443
        $now = dol_now();
1444
1445
        // Initialise parameters
1446
        $this->id = 0;
1447
        $this->ref = 'SPECIMEN';
1448
        $this->ref_client = 'SPECIMEN CLIENT';
1449
        $this->specimen = 1;
1450
        $this->socid = 1;
1451
        $this->datec = $now;
1452
        $this->note_private = 'Private note';
1453
        $this->note_public = 'SPECIMEN';
1454
        $this->duration = 0;
1455
        $nbp = 25;
1456
        $xnbp = 0;
1457
        while ($xnbp < $nbp) {
1458
            $line = new FichinterLigne($this->db);
1459
            $line->desc = $langs->trans("Description") . " " . $xnbp;
1460
            $line->date = ($now - 3600 * (1 + $xnbp));
1461
            $line->datei = ($now - 3600 * (1 + $xnbp)); // For backward compatibility
1462
            $line->duration = 600;
1463
            $line->fk_fichinter = 0;
1464
            $this->lines[$xnbp] = $line;
1465
            $xnbp++;
1466
1467
            $this->duration += $line->duration;
1468
        }
1469
1470
        return 1;
1471
    }
1472
1473
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1474
    /**
1475
     *  Load array lines ->lines
1476
     *
1477
     *  @return     int     Return integer <0 if KO, >0 if OK
1478
     */
1479
    public function fetch_lines()
1480
    {
1481
		// phpcs:enable
1482
        $this->lines = array();
1483
1484
        $sql = "SELECT rowid, fk_fichinter, description, duree, date, rang";
1485
        $sql .= " FROM " . MAIN_DB_PREFIX . "fichinterdet";
1486
        $sql .= " WHERE fk_fichinter = " . ((int) $this->id);
1487
        $sql .= " ORDER BY rang ASC, date ASC";
1488
1489
        dol_syslog(get_class($this) . "::fetch_lines", LOG_DEBUG);
1490
1491
        $resql = $this->db->query($sql);
1492
        if ($resql) {
1493
            $num = $this->db->num_rows($resql);
1494
            $i = 0;
1495
            while ($i < $num) {
1496
                $objp = $this->db->fetch_object($resql);
1497
1498
                $line = new FichinterLigne($this->db);
1499
                $line->id = $objp->rowid;
1500
                $line->fk_fichinter = $objp->fk_fichinter;
1501
                $line->desc = $objp->description;
1502
                $line->duration = $objp->duree;
1503
                //For invoicing we calculing hours
1504
                $line->qty = round($objp->duree / 3600, 2);
1505
                $line->date = $this->db->jdate($objp->date);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($objp->date) can also be of type string. However, the property $date 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...
1506
                $line->datei = $this->db->jdate($objp->date);   // For backward compatibility
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->db->jdate($objp->date) can also be of type string. However, the property $datei 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...
1507
                $line->rang = $objp->rang;
1508
                $line->product_type = 1;
1509
                $line->fetch_optionals();
1510
1511
                $this->lines[$i] = $line;
1512
                $i++;
1513
            }
1514
            $this->db->free($resql);
1515
1516
            return 1;
1517
        } else {
1518
            $this->error = $this->db->error();
1519
            return -1;
1520
        }
1521
    }
1522
1523
    /**
1524
     * Function used to replace a thirdparty id with another one.
1525
     *
1526
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
1527
     * @param   int     $origin_id  Old thirdparty id
1528
     * @param   int     $dest_id    New thirdparty id
1529
     * @return  bool
1530
     */
1531
    public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1532
    {
1533
        $tables = array(
1534
            'fichinter'
1535
        );
1536
1537
        return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1538
    }
1539
1540
    /**
1541
     * Set customer reference number
1542
     *
1543
     *  @param      User    $user           Object user that modify
1544
     *  @param      string  $ref_client     Customer reference
1545
     *  @param      int     $notrigger      1=Does not execute triggers, 0= execute triggers
1546
     *  @return     int                     Return integer <0 if ko, >0 if ok
1547
     */
1548
    public function setRefClient($user, $ref_client, $notrigger = 0)
1549
    {
1550
        // phpcs:enable
1551
        if ($user->hasRight('ficheinter', 'creer')) {
1552
            $error = 0;
1553
1554
            $this->db->begin();
1555
1556
            $this->oldcopy = dol_clone($this, 2);
1557
1558
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . " SET ref_client = " . (empty($ref_client) ? 'NULL' : "'" . $this->db->escape($ref_client) . "'");
1559
            $sql .= " WHERE rowid = " . ((int) $this->id);
1560
1561
            dol_syslog(__METHOD__ . ' $this->id=' . $this->id . ', ref_client=' . $ref_client, LOG_DEBUG);
1562
            $resql = $this->db->query($sql);
1563
            if (!$resql) {
1564
                $this->errors[] = $this->db->error();
1565
                $error++;
1566
            }
1567
1568
            if (!$error) {
1569
                $this->ref_client = $ref_client;
1570
            }
1571
1572
            if (!$notrigger && empty($error)) {
1573
                // Call trigger
1574
                $result = $this->call_trigger('FICHINTER_MODIFY', $user);
1575
                if ($result < 0) {
1576
                    $error++;
1577
                }
1578
                // End call triggers
1579
            }
1580
1581
            if (!$error) {
1582
                $this->db->commit();
1583
                return 1;
1584
            } else {
1585
                foreach ($this->errors as $errmsg) {
1586
                    dol_syslog(__METHOD__ . ' Error: ' . $errmsg, LOG_ERR);
1587
                    $this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
1588
                }
1589
                $this->db->rollback();
1590
                return -1 * $error;
1591
            }
1592
        } else {
1593
            return -1;
1594
        }
1595
    }
1596
1597
    /**
1598
     *  Return clicable link of object (with eventually picto)
1599
     *
1600
     *  @param      string      $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
1601
     *  @param      array       $arraydata              Array of data
1602
     *  @return     string                              HTML Code for Kanban thumb.
1603
     */
1604
    public function getKanbanView($option = '', $arraydata = null)
1605
    {
1606
        global $langs;
1607
1608
        $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1609
1610
        $return = '<div class="box-flex-item box-flex-grow-zero">';
1611
        $return .= '<div class="info-box info-box-sm">';
1612
        $return .= '<span class="info-box-icon bg-infobox-action">';
1613
        $return .= img_picto('', $this->picto);
1614
        $return .= '</span>';
1615
        $return .= '<div class="info-box-content">';
1616
        $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . (method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref) . '</span>';
1617
        if ($selected >= 0) {
1618
            $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
1619
        }
1620
        if (!empty($arraydata['thirdparty'])) {
1621
            $tmpthirdparty = $arraydata['thirdparty'];
1622
            $return .= '<br><span class="info-box-label">' . $tmpthirdparty->getNomUrl(1) . '</span>';
1623
        }
1624
        if (property_exists($this, 'duration')) {
1625
            $return .= '<br><span class="info-box-label ">' . $langs->trans("Duration") . ' : ' . convertSecondToTime($this->duration, 'allhourmin') . '</span>';
1626
        }
1627
        if (method_exists($this, 'getLibStatut')) {
1628
            $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
1629
        }
1630
        $return .= '</div>';
1631
        $return .= '</div>';
1632
        $return .= '</div>';
1633
        return $return;
1634
    }
1635
1636
    /**
1637
     * Set signed status
1638
     *
1639
     * @param  User   $user        Object user that modify
1640
     * @param  int    $status      Newsigned  status to set (often a constant like self::STATUS_XXX)
1641
     * @param  int    $notrigger   1 = Does not execute triggers, 0 = Execute triggers
1642
     * @param  string $triggercode Trigger code to use
1643
     * @return int                 0 < if KO, > 0 if OK
1644
     */
1645
    public function setSignedStatus(User $user, int $status = 0, int $notrigger = 0, $triggercode = ''): int
1646
    {
1647
        return $this->setSignedStatusCommon($user, $status, $notrigger, $triggercode);
1648
    }
1649
}
1650