Passed
Push — EXTRACT_CLASSES ( c25e41...9f3ede )
by Rafael
55:18
created

Delivery::valid()   F

Complexity

Conditions 25
Paths 1301

Size

Total Lines 144
Code Lines 92

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 92
nc 1301
nop 2
dl 0
loc 144
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) 2003       Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2005-2014  Regis Houssin               <[email protected]>
5
 * Copyright (C) 2006-2007  Laurent Destailleur         <[email protected]>
6
 * Copyright (C) 2007       Franky Van Liedekerke       <[email protected]>
7
 * Copyright (C) 2011-2023  Philippe Grand	            <[email protected]>
8
 * Copyright (C) 2013       Florian Henry	            <[email protected]>
9
 * Copyright (C) 2014-2015  Marcos García               <[email protected]>
10
 * Copyright (C) 2023-2024  Frédéric France             <[email protected]>
11
 * Copyright (C) 2024		MDW							<[email protected]>
12
 * Copyright (C) 2024       Rafael San José             <[email protected]>
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 3 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26
 */
27
28
namespace Dolibarr\Code\Delivery\Classes;
29
30
use Dolibarr\Code\Core\Traits\CommonIncoterm;
31
use Dolibarr\Core\Base\CommonObject;
32
use DoliDB;
33
34
/**
35
 *  \file       htdocs/delivery/class/delivery.class.php
36
 *  \ingroup    delivery
37
 *  \brief      Delivery Order Management Class File
38
 */
39
40
require_once constant('DOL_DOCUMENT_ROOT') . '/expedition/class/expedition.class.php';
41
require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/commonincoterm.class.php';
42
require_once constant('DOL_DOCUMENT_ROOT') . '/product/stock/class/mouvementstock.class.php';
43
if (isModEnabled("propal")) {
44
    require_once constant('DOL_DOCUMENT_ROOT') . '/comm/propal/class/propal.class.php';
45
}
46
if (isModEnabled('order')) {
47
    require_once constant('DOL_DOCUMENT_ROOT') . '/commande/class/commande.class.php';
48
}
49
50
51
/**
52
 *  Class to manage receptions
53
 */
54
class Delivery extends CommonObject
55
{
56
    use CommonIncoterm;
0 ignored issues
show
Bug introduced by
The trait Dolibarr\Code\Core\Traits\CommonIncoterm requires the property $code which is not provided by Dolibarr\Code\Delivery\Classes\Delivery.
Loading history...
57
58
    /**
59
     * @var string ID to identify managed object
60
     */
61
    public $element = "delivery";
62
63
    /**
64
     * @var string Field with ID of parent key if this field has a parent
65
     */
66
    public $fk_element = "fk_delivery";
67
68
    /**
69
     * @var string Name of table without prefix where object is stored
70
     */
71
    public $table_element = "delivery";
72
73
    /**
74
     * @var string    Name of subtable line
75
     */
76
    public $table_element_line = "deliverydet";
77
78
    /**
79
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
80
     */
81
    public $picto = 'sending';
82
83
    /**
84
     * @var int draft status
85
     */
86
    public $draft;
87
88
    /**
89
     * @var int thirdparty id
90
     */
91
    public $socid;
92
93
    /**
94
     * @var string ref customer
95
     */
96
    public $ref_customer;
97
98
    /**
99
     * @var integer|string Date really received
100
     */
101
    public $date_delivery;
102
103
    /**
104
     * @var integer|string date_creation
105
     */
106
    public $date_creation;
107
108
    /**
109
     * @var integer|string date_valid
110
     */
111
    public $date_valid;
112
113
    /**
114
     * @var string model pdf
115
     */
116
    public $model_pdf;
117
118
    public $commande_id;
119
120
    /**
121
     * @var DeliveryLine[] lines
122
     */
123
    public $lines = array();
124
125
    /**
126
     * @var int user_author_id
127
     */
128
    public $user_author_id;
129
130
131
    /**
132
     * Constructor
133
     *
134
     * @param   DoliDB  $db     Database handler
135
     */
136
    public function __construct($db)
137
    {
138
        $this->db = $db;
0 ignored issues
show
Documentation Bug introduced by
It seems like $db of type DoliDB is incompatible with the declared type Dolibarr\Core\Base\DoliDB of property $db.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
139
140
        // List of short language codes for status
141
        $this->labelStatus[-1] = 'StatusDeliveryCanceled';
142
        $this->labelStatus[0]  = 'StatusDeliveryDraft';
143
        $this->labelStatus[1]  = 'StatusDeliveryValidated';
144
    }
145
146
    /**
147
     *  Create delivery receipt in database
148
     *
149
     *  @param  User    $user       Object du user qui cree
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Delivery\Classes\User was not found. Did you mean User? If so, make sure to prefix the type with \.
Loading history...
150
     *  @return int                 Return integer <0 si erreur, id delivery cree si ok
151
     */
152
    public function create($user)
153
    {
154
        global $conf;
155
156
        dol_syslog("Delivery::create");
157
158
        if (empty($this->model_pdf)) {
159
            $this->model_pdf = getDolGlobalString('DELIVERY_ADDON_PDF');
160
        }
161
162
        $error = 0;
163
164
        $now = dol_now();
165
166
        /* Delivery note as draft On positionne en mode draft le bon de livraison */
167
        $this->draft = 1;
168
169
        $this->user = $user;
170
171
        $this->db->begin();
172
173
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "delivery (";
174
        $sql .= "ref";
175
        $sql .= ", entity";
176
        $sql .= ", fk_soc";
177
        $sql .= ", ref_customer";
178
        $sql .= ", date_creation";
179
        $sql .= ", fk_user_author";
180
        $sql .= ", date_delivery";
181
        $sql .= ", fk_address";
182
        $sql .= ", note_private";
183
        $sql .= ", note_public";
184
        $sql .= ", model_pdf";
185
        $sql .= ", fk_incoterms, location_incoterms";
186
        $sql .= ") VALUES (";
187
        $sql .= "'(PROV)'";
188
        $sql .= ", " . ((int) $conf->entity);
189
        $sql .= ", " . ((int) $this->socid);
190
        $sql .= ", '" . $this->db->escape($this->ref_customer) . "'";
191
        $sql .= ", '" . $this->db->idate($now) . "'";
192
        $sql .= ", " . ((int) $user->id);
193
        $sql .= ", " . ($this->date_delivery ? "'" . $this->db->idate($this->date_delivery) . "'" : "null");
194
        $sql .= ", " . ($this->fk_delivery_address > 0 ? $this->fk_delivery_address : "null");
195
        $sql .= ", " . (!empty($this->note_private) ? "'" . $this->db->escape($this->note_private) . "'" : "null");
196
        $sql .= ", " . (!empty($this->note_public) ? "'" . $this->db->escape($this->note_public) . "'" : "null");
197
        $sql .= ", " . (!empty($this->model_pdf) ? "'" . $this->db->escape($this->model_pdf) . "'" : "null");
198
        $sql .= ", " . (int) $this->fk_incoterms;
199
        $sql .= ", '" . $this->db->escape($this->location_incoterms) . "'";
200
        $sql .= ")";
201
202
        dol_syslog("Delivery::create", LOG_DEBUG);
203
        $resql = $this->db->query($sql);
204
        if ($resql) {
205
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "delivery");
206
207
            $numref = "(PROV" . $this->id . ")";
208
209
            $sql = "UPDATE " . MAIN_DB_PREFIX . "delivery ";
210
            $sql .= "SET ref = '" . $this->db->escape($numref) . "'";
211
            $sql .= " WHERE rowid = " . ((int) $this->id);
212
213
            dol_syslog("Delivery::create", LOG_DEBUG);
214
            $resql = $this->db->query($sql);
215
            if ($resql) {
216
                if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
217
                    $commande = new Commande($this->db);
218
                    $commande->id = $this->commande_id;
219
                    $commande->fetch_lines();
220
                }
221
222
223
                /*
224
                 *  Inserting products into the database
225
                 */
226
                $num = count($this->lines);
227
                for ($i = 0; $i < $num; $i++) {
228
                    $origin_id = $this->lines[$i]->origin_line_id;
229
                    if (!$origin_id) {
230
                        $origin_id = $this->lines[$i]->commande_ligne_id; // For backward compatibility
231
                    }
232
233
                    if (!$this->create_line($origin_id, $this->lines[$i]->qty, $this->lines[$i]->fk_product, $this->lines[$i]->description, $this->lines[$i]->array_options)) {
234
                        $error++;
235
                    }
236
                }
237
238
                if (!$error && $this->id && $this->origin_id) {
239
                    $ret = $this->add_object_linked();
240
                    if (!$ret) {
241
                        $error++;
242
                    }
243
244
                    if (!getDolGlobalInt('MAIN_SUBMODULE_EXPEDITION')) {
245
                        $ret = $this->setStatut(2, $this->origin_id, $this->origin);
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

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

245
                        $ret = $this->setStatut(2, $this->origin_id, /** @scrutinizer ignore-deprecated */ $this->origin);

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...
246
                        if (!$ret) {
247
                            $error++;
248
                        }
249
                    }
250
                }
251
252
                if (!$error) {
253
                    $this->db->commit();
254
                    return $this->id;
255
                } else {
256
                    $error++;
257
                    $this->error = $this->db->lasterror() . " - sql=" . $this->db->lastqueryerror;
258
                    $this->db->rollback();
259
                    return -3;
260
                }
261
            } else {
262
                $error++;
263
                $this->error = $this->db->lasterror() . " - sql=" . $this->db->lastqueryerror;
264
                $this->db->rollback();
265
                return -2;
266
            }
267
        } else {
268
            $error++;
269
            $this->error = $this->db->lasterror() . " - sql=" . $this->db->lastqueryerror;
270
            $this->db->rollback();
271
            return -1;
272
        }
273
    }
274
275
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
276
    /**
277
     *  Create a line
278
     *
279
     *  @param  string  $origin_id              Id of order
280
     *  @param  string  $qty                    Quantity
281
     *  @param  string  $fk_product             Id of predefined product
282
     *  @param  string  $description            Description
283
     *  @param  array   $array_options          Array options
284
     *  @return int                             Return integer <0 if KO, >0 if OK
285
     */
286
    public function create_line($origin_id, $qty, $fk_product, $description, $array_options = [])
287
    {
288
		// phpcs:enable
289
        $error = 0;
290
        $idprod = $fk_product;
291
292
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "deliverydet (fk_delivery, fk_origin_line,";
293
        $sql .= " fk_product, description, qty)";
294
        $sql .= " VALUES (" . $this->id . "," . ((int) $origin_id) . ",";
295
        $sql .= " " . ($idprod > 0 ? ((int) $idprod) : "null") . ",";
296
        $sql .= " " . ($description ? "'" . $this->db->escape($description) . "'" : "null") . ",";
297
        $sql .= (price2num($qty, 'MS')) . ")";
298
299
        dol_syslog(get_class($this) . "::create_line", LOG_DEBUG);
300
        if (!$this->db->query($sql)) {
301
            $error++;
302
        }
303
304
        $id = $this->db->last_insert_id(MAIN_DB_PREFIX . "deliverydet");
305
306
        if (is_array($array_options) && count($array_options) > 0) {
307
            $line = new DeliveryLine($this->db);
308
            $line->id = $id;
309
            $line->array_options = $array_options;
310
            $result = $line->insertExtraFields();
311
        }
312
313
        if (!$error) {
314
            return 1;
315
        }
316
317
        return -1;
318
    }
319
320
    /**
321
     *  Load a delivery receipt
322
     *
323
     *  @param  int     $id         Id of object to load
324
     *  @return integer
325
     */
326
    public function fetch($id)
327
    {
328
        $sql = "SELECT l.rowid, l.fk_soc, l.date_creation, l.date_valid, l.ref, l.ref_customer, l.fk_user_author,";
329
        $sql .= " l.total_ht, l.fk_statut, l.fk_user_valid, l.note_private, l.note_public";
330
        $sql .= ", l.date_delivery, l.fk_address, l.model_pdf";
331
        $sql .= ", el.fk_source as origin_id, el.sourcetype as origin";
332
        $sql .= ', l.fk_incoterms, l.location_incoterms';
333
        $sql .= ", i.libelle as label_incoterms";
334
        $sql .= " FROM " . MAIN_DB_PREFIX . "delivery as l";
335
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "element_element as el ON el.fk_target = l.rowid AND el.targettype = '" . $this->db->escape($this->element) . "'";
336
        $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_incoterms as i ON l.fk_incoterms = i.rowid';
337
        $sql .= " WHERE l.rowid = " . ((int) $id);
338
339
        dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
340
        $result = $this->db->query($sql);
341
        if ($result) {
342
            if ($this->db->num_rows($result)) {
343
                $obj = $this->db->fetch_object($result);
344
345
                $this->id                   = $obj->rowid;
346
                $this->date_delivery        = $this->db->jdate($obj->date_delivery);
347
                $this->date_creation        = $this->db->jdate($obj->date_creation);
348
                $this->date_valid           = $this->db->jdate($obj->date_valid);
349
                $this->ref                  = $obj->ref;
350
                $this->ref_customer         = $obj->ref_customer;
351
                $this->socid                = $obj->fk_soc;
352
                $this->statut               = $obj->fk_statut;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

352
                /** @scrutinizer ignore-deprecated */ $this->statut               = $obj->fk_statut;

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...
353
                $this->status               = $obj->fk_statut;
354
                $this->user_author_id       = $obj->fk_user_author;
355
                $this->user_validation_id   = $obj->fk_user_valid;
356
                $this->fk_delivery_address  = $obj->fk_address;
357
                $this->note                 = $obj->note_private; //TODO 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

357
                /** @scrutinizer ignore-deprecated */ $this->note                 = $obj->note_private; //TODO 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...
358
                $this->note_private         = $obj->note_private;
359
                $this->note_public          = $obj->note_public;
360
                $this->model_pdf            = $obj->model_pdf;
361
                $this->origin               = $obj->origin; // May be 'shipping'
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

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

361
                /** @scrutinizer ignore-deprecated */ $this->origin               = $obj->origin; // May be 'shipping'

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...
362
                $this->origin_id            = $obj->origin_id; // May be id of shipping
363
364
                //Incoterms
365
                $this->fk_incoterms = $obj->fk_incoterms;
366
                $this->location_incoterms = $obj->location_incoterms;
367
                $this->label_incoterms = $obj->label_incoterms;
368
                $this->db->free($result);
369
370
                if ($this->statut == 0) {
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

370
                if (/** @scrutinizer ignore-deprecated */ $this->statut == 0) {

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...
371
                    $this->draft = 1;
372
                }
373
374
                // Retrieve all extrafields
375
                // fetch optionals attributes and labels
376
                $this->fetch_optionals();
377
378
                // Load lines
379
                $result = $this->fetch_lines();
380
                if ($result < 0) {
381
                    return -3;
382
                }
383
384
                return 1;
385
            } else {
386
                $this->error = 'Delivery with id ' . $id . ' not found sql=' . $sql;
387
                dol_syslog(get_class($this) . '::fetch Error ' . $this->error, LOG_ERR);
388
                return -2;
389
            }
390
        } else {
391
            $this->error = $this->db->error();
392
            return -1;
393
        }
394
    }
395
396
    /**
397
     *  Validate object and update stock if option enabled
398
     *
399
     *  @param  User    $user       Object user that validate
400
     *  @param  int     $notrigger  1=Does not execute triggers, 0= execute triggers
401
     *  @return int
402
     */
403
    public function valid($user, $notrigger = 0)
404
    {
405
        global $conf;
406
407
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
408
409
        dol_syslog(get_class($this) . "::valid begin");
410
411
        $this->db->begin();
412
413
        $error = 0;
414
415
        if (
416
            (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'delivery', 'creer'))
417
            || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'delivery_advance', 'validate'))
418
        ) {
419
            if (getDolGlobalString('DELIVERY_ADDON_NUMBER')) {
420
                // Setting the command numbering module name
421
                $modName = getDolGlobalString('DELIVERY_ADDON_NUMBER');
422
423
                if (is_readable(DOL_DOCUMENT_ROOT . '/core/modules/delivery/' . $modName . '.php')) {
424
                    require_once constant('DOL_DOCUMENT_ROOT') . '/core/modules/delivery/' . $modName . '.php';
425
426
                    $now = dol_now();
427
428
                    // Retrieving the new reference
429
                    $objMod = new $modName($this->db);
430
                    $soc = new Societe($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Delivery\Classes\Societe was not found. Did you mean Societe? If so, make sure to prefix the type with \.
Loading history...
431
                    $soc->fetch($this->socid);
432
433
                    if (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref)) { // empty should not happened, but when it occurs, the test save life
434
                        $numref = $objMod->delivery_get_num($soc, $this);
435
                    } else {
436
                        $numref = $this->ref;
437
                    }
438
                    $this->newref = dol_sanitizeFileName($numref);
439
440
                    // Test if is not already in valid status. If so, we stop to avoid decrementing the stock twice.
441
                    $sql = "SELECT ref";
442
                    $sql .= " FROM " . MAIN_DB_PREFIX . "delivery";
443
                    $sql .= " WHERE ref = '" . $this->db->escape($numref) . "'";
444
                    $sql .= " AND fk_statut <> 0";
445
                    $sql .= " AND entity = " . ((int) $conf->entity);
446
447
                    $resql = $this->db->query($sql);
448
                    if ($resql) {
449
                        $num = $this->db->num_rows($resql);
450
                        if ($num > 0) {
451
                            return 0;
452
                        }
453
                    }
454
455
                    $sql = "UPDATE " . MAIN_DB_PREFIX . "delivery SET";
456
                    $sql .= " ref='" . $this->db->escape($numref) . "'";
457
                    $sql .= ", fk_statut = 1";
458
                    $sql .= ", date_valid = '" . $this->db->idate($now) . "'";
459
                    $sql .= ", fk_user_valid = " . $user->id;
460
                    $sql .= " WHERE rowid = " . ((int) $this->id);
461
                    $sql .= " AND fk_statut = 0";
462
463
                    $resql = $this->db->query($sql);
464
                    if (!$resql) {
465
                        dol_print_error($this->db);
466
                        $this->error = $this->db->lasterror();
467
                        $error++;
468
                    }
469
470
                    if (!$error && !$notrigger) {
471
                        // Call trigger
472
                        $result = $this->call_trigger('DELIVERY_VALIDATE', $user);
473
                        if ($result < 0) {
474
                            $error++;
475
                        }
476
                        // End call triggers
477
                    }
478
479
                    if (!$error) {
480
                        $this->oldref = $this->ref;
481
482
                        // Rename directory if dir was a temporary ref
483
                        if (preg_match('/^[\(]?PROV/i', $this->ref)) {
484
                            // Now we rename also files into index
485
                            $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'expedition/receipt/" . $this->db->escape($this->newref) . "'";
486
                            $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'expedition/receipt/" . $this->db->escape($this->ref) . "' and entity = " . ((int) $conf->entity);
487
                            $resql = $this->db->query($sql);
488
                            if (!$resql) {
489
                                $error++;
490
                                $this->error = $this->db->lasterror();
491
                            }
492
                            $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'expedition/receipt/" . $this->db->escape($this->newref) . "'";
493
                            $sql .= " WHERE filepath = 'expedition/receipt/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
494
                            $resql = $this->db->query($sql);
495
                            if (!$resql) {
496
                                $error++;
497
                                $this->error = $this->db->lasterror();
498
                            }
499
500
                            // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
501
                            $oldref = dol_sanitizeFileName($this->ref);
502
                            $newref = dol_sanitizeFileName($numref);
503
                            $dirsource = $conf->expedition->dir_output . '/receipt/' . $oldref;
504
                            $dirdest = $conf->expedition->dir_output . '/receipt/' . $newref;
505
                            if (!$error && file_exists($dirsource)) {
506
                                dol_syslog(get_class($this) . "::valid rename dir " . $dirsource . " into " . $dirdest);
507
508
                                if (@rename($dirsource, $dirdest)) {
509
                                    dol_syslog("Rename ok");
510
                                    // Rename docs starting with $oldref with $newref
511
                                    $listoffiles = dol_dir_list($conf->expedition->dir_output . '/receipt/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/'));
512
                                    foreach ($listoffiles as $fileentry) {
513
                                        $dirsource = $fileentry['name'];
514
                                        $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource);
515
                                        $dirsource = $fileentry['path'] . '/' . $dirsource;
516
                                        $dirdest = $fileentry['path'] . '/' . $dirdest;
517
                                        @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

517
                                        /** @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...
518
                                    }
519
                                }
520
                            }
521
                        }
522
523
                        // Set new ref and current status
524
                        if (!$error) {
525
                            $this->ref = $numref;
526
                            $this->statut = 1;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

526
                            /** @scrutinizer ignore-deprecated */ $this->statut = 1;

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...
527
                        }
528
529
                        dol_syslog(get_class($this) . "::valid ok");
530
                    }
531
532
                    if (!$error) {
533
                        $this->db->commit();
534
                        return 1;
535
                    } else {
536
                        $this->db->rollback();
537
                        return -1;
538
                    }
539
                }
540
            }
541
542
            return -1;
543
        } else {
544
            $this->error = "NotAllowed";
545
            dol_syslog(get_class($this) . "::valid " . $this->error, LOG_ERR);
546
            return -1;
547
        }
548
    }
549
550
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
551
    /**
552
     *  Creating the delivery slip from an existing shipment
553
     *
554
     *  @param  User    $user           User who creates
555
     *  @param  int     $sending_id     Id of the expedition that serves as a model
556
     *  @return integer                 Return integer <=0 if KO, >0 if OK
557
     */
558
    public function create_from_sending($user, $sending_id)
559
    {
560
		// phpcs:enable
561
        global $conf;
562
563
        $expedition = new Expedition($this->db);
564
        $result = $expedition->fetch($sending_id);
565
        if ($result <= 0) {
566
            return $result;
567
        }
568
569
        $this->lines = array();
570
571
        $num = count($expedition->lines);
572
        for ($i = 0; $i < $num; $i++) {
573
            $line = new DeliveryLine($this->db);
574
            $line->origin_line_id    = $expedition->lines[$i]->origin_line_id;
575
            $line->label             = $expedition->lines[$i]->label;
576
            $line->description       = $expedition->lines[$i]->description;
577
            $line->qty               = $expedition->lines[$i]->qty_shipped;
578
            $line->fk_product        = $expedition->lines[$i]->fk_product;
579
            if (!getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($expedition->lines[$i]->array_options) && count($expedition->lines[$i]->array_options) > 0) { // For avoid conflicts if trigger used
580
                $line->array_options = $expedition->lines[$i]->array_options;
581
            }
582
            $this->lines[$i] = $line;
583
        }
584
585
        $this->origin               = $expedition->element;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

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

585
        /** @scrutinizer ignore-deprecated */ $this->origin               = $expedition->element;

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...
586
        $this->origin_id            = $expedition->id;
587
        $this->note_private         = $expedition->note_private;
588
        $this->note_public          = $expedition->note_public;
589
        $this->fk_project           = $expedition->fk_project;
590
        $this->date_delivery        = $expedition->date_delivery;
591
        $this->fk_delivery_address  = $expedition->fk_delivery_address;
592
        $this->socid                = $expedition->socid;
593
        $this->ref_customer         = $expedition->ref_customer;
594
595
        //Incoterms
596
        $this->fk_incoterms = $expedition->fk_incoterms;
597
        $this->location_incoterms = $expedition->location_incoterms;
598
599
        return $this->create($user);
600
    }
601
602
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
603
    /**
604
     * Update a livraison line (only extrafields)
605
     *
606
     * @param   int     $id                 Id of line (livraison line)
607
     * @param   array   $array_options      extrafields array
608
     * @return  int                         Return integer <0 if KO, >0 if OK
609
     */
610
    public function update_line($id, $array_options = [])
611
    {
612
		// phpcs:enable
613
        global $conf;
614
        $error = 0;
615
616
        if ($id > 0 && !$error && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
617
            $line = new DeliveryLine($this->db);
618
            $line->array_options = $array_options;
619
            $line->id = $id;
620
            $result = $line->insertExtraFields();
621
622
            if ($result < 0) {
623
                $this->errors[] = $line->error;
624
                $error++;
625
            }
626
        }
627
628
        if (!$error) {
629
            return 1;
630
        } else {
631
            return -1;
632
        }
633
    }
634
635
636
    /**
637
     *  Add line
638
     *
639
     *  @param  int     $origin_id              Origin id
640
     *  @param  float   $qty                    Qty
641
     *  @param  array   $array_options          Array options
642
     *  @return void
643
     */
644
    public function addline($origin_id, $qty, $array_options = [])
645
    {
646
        global $conf;
647
648
        $num = count($this->lines);
649
        $line = new DeliveryLine($this->db);
650
651
        $line->origin_id = $origin_id;
652
        $line->qty = $qty;
653
        if (!getDolGlobalString('MAIN_EXTRAFIELDS_DISABLED') && is_array($array_options) && count($array_options) > 0) { // For avoid conflicts if trigger used
654
            $line->array_options = $array_options;
655
        }
656
        $this->lines[$num] = $line;
657
    }
658
659
    /**
660
     *  Delete line
661
     *
662
     *  @param  int     $lineid     Line id
663
     *  @return integer             Return integer <0 if KO, 0 if nothing done, >0 if OK
664
     */
665
    public function deleteLine($lineid)
666
    {
667
        if ($this->statut == 0) {
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

667
        if (/** @scrutinizer ignore-deprecated */ $this->statut == 0) {

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...
668
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . "commandedet";
669
            $sql .= " WHERE rowid = " . ((int) $lineid);
670
671
            if ($this->db->query($sql)) {
672
                $this->update_price(1);
673
674
                return 1;
675
            } else {
676
                return -1;
677
            }
678
        }
679
680
        return 0;
681
    }
682
683
    /**
684
     * Delete object
685
     *
686
     * @param   User        $user       User making the deletion
687
     * @return  integer
688
     */
689
    public function delete($user = null)
690
    {
691
        global $conf, $langs;
692
693
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
694
695
        $this->db->begin();
696
697
        $error = 0;
698
699
        $sql = "DELETE FROM " . MAIN_DB_PREFIX . "deliverydet";
700
        $sql .= " WHERE fk_delivery = " . ((int) $this->id);
701
        if ($this->db->query($sql)) {
702
            // Delete linked object
703
            $res = $this->deleteObjectLinked();
704
            if ($res < 0) {
705
                $error++;
706
            }
707
708
            if (!$error) {
709
                $sql = "DELETE FROM " . MAIN_DB_PREFIX . "delivery";
710
                $sql .= " WHERE rowid = " . ((int) $this->id);
711
                if ($this->db->query($sql)) {
712
                    $this->db->commit();
713
714
                    // Deleting pdf folder's draft On efface le repertoire de pdf provisoire
715
                    $ref = dol_sanitizeFileName($this->ref);
716
                    if (!empty($conf->expedition->dir_output)) {
717
                        $dir = $conf->expedition->dir_output . '/receipt/' . $ref;
718
                        $file = $dir . '/' . $ref . '.pdf';
719
                        if (file_exists($file)) {
720
                            if (!dol_delete_file($file)) {
721
                                return 0;
722
                            }
723
                        }
724
                        if (file_exists($dir)) {
725
                            if (!dol_delete_dir($dir)) {
726
                                $this->error = $langs->trans("ErrorCanNotDeleteDir", $dir);
727
                                return 0;
728
                            }
729
                        }
730
                    }
731
732
                    // Call trigger
733
                    $result = $this->call_trigger('DELIVERY_DELETE', $user);
734
                    if ($result < 0) {
735
                        $this->db->rollback();
736
                        return -4;
737
                    }
738
                    // End call triggers
739
740
                    return 1;
741
                } else {
742
                    $this->error = $this->db->lasterror() . " - sql=$sql";
743
                    $this->db->rollback();
744
                    return -3;
745
                }
746
            } else {
747
                $this->error = $this->db->lasterror() . " - sql=$sql";
748
                $this->db->rollback();
749
                return -2;
750
            }
751
        } else {
752
            $this->error = $this->db->lasterror() . " - sql=$sql";
753
            $this->db->rollback();
754
            return -1;
755
        }
756
    }
757
758
    /**
759
     * getTooltipContentArray
760
     * @param array $params params to construct tooltip data
761
     * @since v18
762
     * @return array
763
     */
764
    public function getTooltipContentArray($params)
765
    {
766
        global $langs;
767
768
        $langs->load('deliveries');
769
770
        $datas = [];
771
772
        $datas['picto'] = img_picto('', $this->picto) . ' <u>' . $langs->trans("ShowReceiving") . '</u>:<br>';
773
        $datas['picto'] .= '<b>' . $langs->trans("Status") . '</b>: ' . $this->ref;
774
775
        return $datas;
776
    }
777
778
    /**
779
     *  Return clicable name (with picto eventually)
780
     *
781
     *  @param  int     $withpicto                  0=No picto, 1=Include picto into link, 2=Only picto
782
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
783
     *  @return string                              Chaine avec URL
784
     */
785
    public function getNomUrl($withpicto = 0, $save_lastsearch_value = -1)
786
    {
787
        global $langs, $hookmanager;
788
789
        $result = '';
790
791
        $params = [
792
            'id' => $this->id,
793
            'objecttype' => $this->element,
794
        ];
795
        $classfortooltip = 'classfortooltip';
796
        $dataparams = '';
797
        if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
798
            $classfortooltip = 'classforajaxtooltip';
799
            $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"';
800
            $label = '';
801
        } else {
802
            $label = implode($this->getTooltipContentArray($params));
803
        }
804
805
        $url = constant('BASE_URL') . '/delivery/card.php?id=' . $this->id;
806
807
        //if ($option !== 'nolink')
808
        //{
809
        // Add param to save lastsearch_values or not
810
        $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
811
        if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
812
            $add_save_lastsearch_values = 1;
813
        }
814
        if ($add_save_lastsearch_values) {
815
            $url .= '&save_lastsearch_values=1';
816
        }
817
        //}
818
819
        $linkstart = '<a href="' . $url . '"';
820
        $linkstart .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"');
821
        $linkstart .= $dataparams . ' class="' . $classfortooltip . '">';
822
        $linkend = '</a>';
823
824
        if ($withpicto) {
825
            $result .= ($linkstart . img_object($label, $this->picto, $dataparams . ' class="' . $classfortooltip . '"') . $linkend);
826
        }
827
        if ($withpicto && $withpicto != 2) {
828
            $result .= ' ';
829
        }
830
        $result .= $linkstart . $this->ref . $linkend;
831
832
        global $action;
833
        $hookmanager->initHooks(array($this->element . 'dao'));
834
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
835
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
836
        if ($reshook > 0) {
837
            $result = $hookmanager->resPrint;
838
        } else {
839
            $result .= $hookmanager->resPrint;
840
        }
841
        return $result;
842
    }
843
844
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
845
    /**
846
     *  Load lines insto $this->lines.
847
     *
848
     *  @return     int                             Return integer <0 if KO, >0 if OK
849
     */
850
    public function fetch_lines()
851
    {
852
		// phpcs:enable
853
        $this->lines = array();
854
855
        $sql = "SELECT ld.rowid, ld.fk_product, ld.description, ld.subprice, ld.total_ht, ld.qty as qty_shipped, ld.fk_origin_line, ";
856
        $sql .= " cd.qty as qty_asked, cd.label as custom_label, cd.fk_unit,";
857
        $sql .= " p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc,";
858
        $sql .= " p.weight, p.weight_units,  p.width, p.width_units, p.length, p.length_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tobatch as product_tobatch";
859
        $sql .= " FROM " . MAIN_DB_PREFIX . "commandedet as cd, " . MAIN_DB_PREFIX . "deliverydet as ld";
860
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p on p.rowid = ld.fk_product";
861
        $sql .= " WHERE ld.fk_origin_line = cd.rowid";
862
        $sql .= " AND ld.fk_delivery = " . ((int) $this->id);
863
864
        dol_syslog(get_class($this) . "::fetch_lines", LOG_DEBUG);
865
        $resql = $this->db->query($sql);
866
        if ($resql) {
867
            $num = $this->db->num_rows($resql);
868
            $i = 0;
869
            while ($i < $num) {
870
                $obj = $this->db->fetch_object($resql);
871
872
                $line = new DeliveryLine($this->db);
873
874
                $line->id = $obj->rowid;
875
                $line->label = $obj->custom_label;
876
                $line->description  = $obj->description;
877
                $line->fk_product   = $obj->fk_product;
878
                $line->qty_asked    = $obj->qty_asked;
879
                $line->qty_shipped  = $obj->qty_shipped;
880
881
                $line->product_label    = $obj->product_label; // Product label
882
                $line->product_ref      = $obj->product_ref; // Product ref
883
                $line->product_desc     = $obj->product_desc; // Product description
884
                $line->product_type     = $obj->fk_product_type;
885
886
                $line->fk_origin_line = $obj->fk_origin_line;
887
888
                $line->price = $obj->subprice;
889
                $line->total_ht = $obj->total_ht;
890
891
                // units
892
                $line->weight           = $obj->weight;
893
                $line->weight_units     = $obj->weight_units;
894
                $line->width            = $obj->width;
895
                $line->width_units      = $obj->width_units;
896
                $line->height           = $obj->height;
897
                $line->height_units     = $obj->height_units;
898
                $line->length           = $obj->length;
899
                $line->length_units     = $obj->length_units;
900
                $line->surface          = $obj->surface;
901
                $line->surface_units = $obj->surface_units;
902
                $line->volume           = $obj->volume;
903
                $line->volume_units     = $obj->volume_units;
904
905
                $line->fk_unit = $obj->fk_unit;
906
                $line->fetch_optionals();
907
908
                $this->lines[$i] = $line;
909
910
                $i++;
911
            }
912
            $this->db->free($resql);
913
914
            return 1;
915
        } else {
916
            return -1;
917
        }
918
    }
919
920
921
    /**
922
     *  Return the label of the status
923
     *
924
     *  @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
925
     *  @return string                 Label of status
926
     */
927
    public function getLibStatut($mode = 0)
928
    {
929
        return $this->LibStatut($this->statut, $mode);
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$statut has been deprecated: Use $status instead. ( Ignorable by Annotation )

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

929
        return $this->LibStatut(/** @scrutinizer ignore-deprecated */ $this->statut, $mode);

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...
930
    }
931
932
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
933
    /**
934
     *  Return the label of a given status
935
     *
936
     *  @param  int     $status        Id status
937
     *  @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
938
     *  @return string                 Label of status
939
     */
940
    public function LibStatut($status, $mode)
941
    {
942
		// phpcs:enable
943
        global $langs;
944
945
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
946
            global $langs;
947
            //$langs->load("mymodule");
948
            $this->labelStatus[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
949
            $this->labelStatus[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
950
            $this->labelStatus[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
951
            $this->labelStatusShort[-1] = $langs->transnoentitiesnoconv('StatusDeliveryCanceled');
952
            $this->labelStatusShort[0] = $langs->transnoentitiesnoconv('StatusDeliveryDraft');
953
            $this->labelStatusShort[1] = $langs->transnoentitiesnoconv('StatusDeliveryValidated');
954
        }
955
956
        $statusType = 'status0';
957
        if ($status == -1) {
958
            $statusType = 'status5';
959
        }
960
        if ($status == 1) {
961
            $statusType = 'status4';
962
        }
963
964
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
965
    }
966
967
968
    /**
969
     *  Initialise an instance with random values.
970
     *  Used to build previews or test instances.
971
     *  id must be 0 if object instance is a specimen.
972
     *
973
     *  @return int
974
     */
975
    public function initAsSpecimen()
976
    {
977
        $now = dol_now();
978
979
        // Load array of products prodids
980
        $num_prods = 0;
981
        $prodids = array();
982
        $sql = "SELECT rowid";
983
        $sql .= " FROM " . MAIN_DB_PREFIX . "product";
984
        $sql .= " WHERE entity IN (" . getEntity('product') . ")";
985
        $sql .= " AND tosell = 1";
986
        $sql .= $this->db->plimit(100);
987
988
        $resql = $this->db->query($sql);
989
        if ($resql) {
990
            $num_prods = $this->db->num_rows($resql);
991
            $i = 0;
992
            while ($i < $num_prods) {
993
                $i++;
994
                $row = $this->db->fetch_row($resql);
995
                $prodids[$i] = $row[0];
996
            }
997
        }
998
999
        // Initialise parameters
1000
        $this->id = 0;
1001
        $this->ref = 'SPECIMEN';
1002
        $this->specimen = 1;
1003
        $this->socid = 1;
1004
        $this->date_delivery = $now;
1005
        $this->note_public = 'Public note';
1006
        $this->note_private = 'Private note';
1007
1008
        $i = 0;
1009
        $line = new DeliveryLine($this->db);
1010
        $line->fk_product     = reset($prodids);
1011
        $line->qty_asked      = 10;
1012
        $line->qty_shipped    = 9;
1013
        $line->ref            = 'REFPROD';
1014
        $line->label          = 'Specimen';
1015
        $line->description    = 'Description';
1016
        $line->price          = 100;
1017
        $line->total_ht       = 100;
1018
1019
        $this->lines[$i] = $line;
1020
1021
        return 1;
1022
    }
1023
1024
    /**
1025
     *  Renvoie la quantite de produit restante a livrer pour une commande
1026
     *
1027
     *  @return     array|int       Product remaining to be delivered or <0 if KO
1028
     *  TODO use new function
1029
     */
1030
    public function getRemainingDelivered()
1031
    {
1032
        // Get the linked object
1033
        $this->fetchObjectLinked('', '', $this->id, $this->element);
1034
        //var_dump($this->linkedObjectsIds);
1035
        // Get the product ref and qty in source
1036
        $sqlSourceLine = "SELECT st.rowid, st.description, st.qty";
1037
        $sqlSourceLine .= ", p.ref, p.label";
1038
        $sqlSourceLine .= " FROM " . MAIN_DB_PREFIX . $this->linkedObjectsIds[0]['type'] . "det as st";
1039
        $sqlSourceLine .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON st.fk_product = p.rowid";
1040
        $sqlSourceLine .= " WHERE fk_" . $this->linked_objects[0]['type'] . " = " . ((int) $this->linked_objects[0]['linkid']);
1041
1042
        $resultSourceLine = $this->db->query($sqlSourceLine);
1043
        if ($resultSourceLine) {
1044
            $num_lines = $this->db->num_rows($resultSourceLine);
1045
            $i = 0;
1046
            $array = array();
1047
            while ($i < $num_lines) {
1048
                $objSourceLine = $this->db->fetch_object($resultSourceLine);
1049
1050
                // Get lines of sources already delivered
1051
                $sql = "SELECT ld.fk_origin_line, sum(ld.qty) as qty";
1052
                $sql .= " FROM " . MAIN_DB_PREFIX . "deliverydet as ld, " . MAIN_DB_PREFIX . "delivery as l,";
1053
                $sql .= " " . MAIN_DB_PREFIX . $this->linked_objects[0]['type'] . " as c";
1054
                $sql .= ", " . MAIN_DB_PREFIX . $this->linked_objects[0]['type'] . "det as cd";
1055
                $sql .= " WHERE ld.fk_delivery = l.rowid";
1056
                $sql .= " AND ld.fk_origin_line = cd.rowid";
1057
                $sql .= " AND cd.fk_" . $this->linked_objects[0]['type'] . " = c.rowid";
1058
                $sql .= " AND cd.fk_" . $this->linked_objects[0]['type'] . " = " . ((int) $this->linked_objects[0]['linkid']);
1059
                $sql .= " AND ld.fk_origin_line = " . ((int) $objSourceLine->rowid);
1060
                $sql .= " GROUP BY ld.fk_origin_line";
1061
1062
                $result = $this->db->query($sql);
1063
                $row = $this->db->fetch_row($result);
1064
1065
                if ($objSourceLine->qty - $row[1] > 0) {
1066
                    if ($row[0] == $objSourceLine->rowid) {
1067
                        $array[$i]['qty'] = $objSourceLine->qty - $row[1];
1068
                    } else {
1069
                        $array[$i]['qty'] = $objSourceLine->qty;
1070
                    }
1071
1072
                    $array[$i]['ref'] = $objSourceLine->ref;
1073
                    $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1074
                } elseif ($objSourceLine->qty - $row[1] < 0) {
1075
                    $array[$i]['qty'] = $objSourceLine->qty - $row[1] . " Erreur livraison !";
1076
                    $array[$i]['ref'] = $objSourceLine->ref;
1077
                    $array[$i]['label'] = $objSourceLine->label ? $objSourceLine->label : $objSourceLine->description;
1078
                }
1079
1080
                $i++;
1081
            }
1082
            return $array;
1083
        } else {
1084
            $this->error = $this->db->error() . " - sql=$sqlSourceLine";
1085
            return -1;
1086
        }
1087
    }
1088
1089
    /**
1090
     *  Set the planned delivery date
1091
     *
1092
     *  @param      User            $user               Object utilisateur qui modifie
1093
     *  @param      integer         $delivery_date     Delivery date
1094
     *  @return     int                                 Return integer <0 if KO, >0 if OK
1095
     */
1096
    public function setDeliveryDate($user, $delivery_date)
1097
    {
1098
        if ($user->hasRight('expedition', 'creer')) {
1099
            $sql = "UPDATE " . MAIN_DB_PREFIX . "delivery";
1100
            $sql .= " SET date_delivery = " . ($delivery_date ? "'" . $this->db->idate($delivery_date) . "'" : 'null');
1101
            $sql .= " WHERE rowid = " . ((int) $this->id);
1102
1103
            dol_syslog(get_class($this) . "::setDeliveryDate", LOG_DEBUG);
1104
            $resql = $this->db->query($sql);
1105
            if ($resql) {
1106
                $this->date_delivery = $delivery_date;
1107
                return 1;
1108
            } else {
1109
                $this->error = $this->db->error();
1110
                return -1;
1111
            }
1112
        } else {
1113
            return -2;
1114
        }
1115
    }
1116
1117
    /**
1118
     *  Create object on disk
1119
     *
1120
     *  @param     string       $modele         force le modele a utiliser ('' to not force)
1121
     *  @param     Translate    $outputlangs    Object langs to use for output
1122
     *  @param     int          $hidedetails    Hide details of lines
1123
     *  @param     int          $hidedesc       Hide description
1124
     *  @param     int          $hideref        Hide ref
1125
     *  @return    int                          0 if KO, 1 if OK
1126
     */
1127
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
1128
    {
1129
        global $conf, $langs;
1130
1131
        $langs->load("deliveries");
1132
        $outputlangs->load("products");
1133
1134
        if (!dol_strlen($modele)) {
1135
            $modele = 'typhon';
1136
1137
            if ($this->model_pdf) {
1138
                $modele = $this->model_pdf;
1139
            } elseif (getDolGlobalString('DELIVERY_ADDON_PDF')) {
1140
                $modele = getDolGlobalString('DELIVERY_ADDON_PDF');
1141
            }
1142
        }
1143
1144
        $modelpath = "core/modules/delivery/doc/";
1145
1146
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
1147
    }
1148
1149
    /**
1150
     * Function used to replace a thirdparty id with another one.
1151
     *
1152
     * @param   DoliDB  $dbs        Database handler, because function is static we name it $dbs not $db to avoid breaking coding test
1153
     * @param   int     $origin_id  Old thirdparty id
1154
     * @param   int     $dest_id    New thirdparty id
1155
     * @return  bool
1156
     */
1157
    public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
1158
    {
1159
        $tables = array(
1160
            'delivery'
1161
        );
1162
1163
        return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
1164
    }
1165
1166
    /**
1167
     * Function used to replace a product id with another one.
1168
     *
1169
     * @param DoliDB $db Database handler
1170
     * @param int $origin_id Old product id
1171
     * @param int $dest_id New product id
1172
     * @return bool
1173
     */
1174
    public static function replaceProduct(DoliDB $db, $origin_id, $dest_id)
1175
    {
1176
        $tables = array(
1177
            'deliverydet'
1178
        );
1179
1180
        return CommonObject::commonReplaceProduct($db, $origin_id, $dest_id, $tables);
1181
    }
1182
}
1183
1184
1185
/**
1186
 *  Management class of delivery note lines
1187
 */
1188
class DeliveryLine extends CommonObjectLine
1189
{
1190
    /**
1191
     * @var DoliDB Database handler.
1192
     */
1193
    public $db;
1194
1195
    /**
1196
     * @var string ID to identify managed object
1197
     */
1198
    public $element = 'deliverydet';
1199
1200
    /**
1201
     * @var string Name of table without prefix where object is stored
1202
     */
1203
    public $table_element = 'deliverydet';
1204
1205
    /**
1206
     * @var string delivery note lines label
1207
     */
1208
    public $label;
1209
1210
    /**
1211
     * @var string product description
1212
     */
1213
    public $description;
1214
1215
    /**
1216
     * @deprecated
1217
     * @see $product_ref
1218
     */
1219
    public $ref;
1220
    /**
1221
     * @deprecated
1222
     * @see product_label;
1223
     */
1224
    public $libelle;
1225
1226
    // From llx_expeditiondet
1227
    /**
1228
     * @var float Quantity
1229
     */
1230
    public $qty;
1231
1232
    /**
1233
     * @var float Quantity asked
1234
     */
1235
    public $qty_asked;
1236
1237
    /**
1238
     * @var float Quantity shiiped
1239
     */
1240
    public $qty_shipped;
1241
1242
    public $fk_product;
1243
    public $product_desc;
1244
    public $product_type;
1245
    public $product_ref;
1246
    public $product_label;
1247
1248
    public $price;
1249
1250
    public $fk_origin_line;
1251
    public $origin_id;
1252
1253
    /**
1254
     * @var int origin line ID
1255
     */
1256
    public $origin_line_id;
1257
1258
    /**
1259
     * @var int origin line ID
1260
     * @deprecated
1261
     * @see $origin_line_id
1262
     */
1263
    public $commande_ligne_id;
1264
1265
1266
    /**
1267
     *  Constructor
1268
     *
1269
     *  @param  DoliDB  $db     Database handler
1270
     */
1271
    public function __construct($db)
1272
    {
1273
        $this->db = $db;
1274
    }
1275
}
1276