Passed
Push — main ( f1540e...02d90d )
by Rafael
45:15
created

Entrepot::getNomUrl()   F

Complexity

Conditions 25
Paths 7200

Size

Total Lines 77
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 52
nc 7200
nop 6
dl 0
loc 77
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-2006 Rodolphe Quiedeville     <[email protected]>
4
 * Copyright (C) 2004-2010 Laurent Destailleur      <[email protected]>
5
 * Copyright (C) 2005-2008 Regis Houssin            <[email protected]>
6
 * Copyright (C) 2011	   Juanjo Menent            <[email protected]>
7
 * Copyright (C) 2016	   Francis Appels           <[email protected]>
8
 * Copyright (C) 2019-2024  Frédéric France         <[email protected]>
9
 * Copyright (C) 2024		MDW						<[email protected]>
10
 * Copyright (C) 2024       Rafael San José         <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24
 */
25
26
/**
27
 *  \file       htdocs/product/stock/class/entrepot.class.php
28
 *  \ingroup    stock
29
 *  \brief      File for class to manage warehouses
30
 */
31
32
use DoliCore\Base\GenericDocument;
33
34
/**
35
 *  Class to manage warehouses
36
 */
37
class Entrepot extends GenericDocument
38
{
39
    /**
40
     * @var string ID to identify managed object
41
     */
42
    public $element = 'stock';
43
44
    /**
45
     * @var string Name of table without prefix where object is stored
46
     */
47
    public $table_element = 'entrepot';
48
49
    /**
50
     * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
51
     */
52
    public $picto = 'stock';
53
54
    /**
55
     * @var int 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
56
     */
57
    public $ismultientitymanaged = 1;
58
59
    /**
60
     * @var string  Label
61
     * @deprecated
62
     * @see $label
63
     */
64
    public $libelle;
65
66
    /**
67
     * @var string  Label
68
     */
69
    public $label;
70
71
    /**
72
     * @var string description
73
     */
74
    public $description;
75
76
    public $statut;
77
78
    /**
79
     * @var string Place
80
     */
81
    public $lieu;
82
83
    /**
84
     * @var string Address
85
     */
86
    public $address;
87
88
    /**
89
     * @var string Zipcode
90
     */
91
    public $zip;
92
93
    /**
94
     * @var string Town
95
     */
96
    public $town;
97
98
    /**
99
     * @var string Phone
100
     */
101
    public $phone;
102
103
    /**
104
     * @var string Fax
105
     */
106
    public $fax;
107
108
    /**
109
     * @var int ID of parent
110
     */
111
    public $fk_parent;
112
113
    /**
114
     * @var int ID of project
115
     */
116
    public $fk_project;
117
118
    /**
119
     * @var array List of short language codes for status
120
     */
121
    public $labelStatus = array();
122
123
124
    /**
125
     * @var array<string,array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array<int,string>,comment?:string}>  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string,array{type:...ring>,comment?:string}> at position 16 could not be parsed: Expected '}' at position 16, but found 'int'.
Loading history...
126
     */
127
    public $fields = array(
128
        'rowid' => array('type' => 'integer', 'label' => 'ID', 'enabled' => 1, 'visible' => 0, 'notnull' => 1, 'position' => 10),
129
        'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'default' => '1', 'notnull' => 1, 'index' => 1, 'position' => 15),
130
        'ref' => array('type' => 'varchar(255)', 'label' => 'Ref', 'enabled' => 1, 'visible' => 1, 'showoncombobox' => 1, 'position' => 25, 'searchall' => 1),
131
        'description' => array('type' => 'text', 'label' => 'Description', 'enabled' => 1, 'visible' => -2, 'position' => 35, 'searchall' => 1),
132
        'lieu' => array('type' => 'varchar(64)', 'label' => 'LocationSummary', 'enabled' => 1, 'visible' => 1, 'position' => 40, 'showoncombobox' => 2, 'searchall' => 1),
133
        'fk_parent' => array('type' => 'integer:Entrepot:product/stock/class/entrepot.class.php:1:((statut:=:1) AND (entity:IN:__SHARED_ENTITIES__))', 'label' => 'ParentWarehouse', 'enabled' => 1, 'visible' => -2, 'position' => 41),
134
        'fk_project' => array('type' => 'integer:Project:projet/class/project.class.php:1:(fk_statut:=:1)', 'label' => 'Project', 'enabled' => '$conf->project->enabled', 'visible' => -1, 'position' => 25),
135
        'address' => array('type' => 'varchar(255)', 'label' => 'Address', 'enabled' => 1, 'visible' => -2, 'position' => 45, 'searchall' => 1),
136
        'zip' => array('type' => 'varchar(10)', 'label' => 'Zip', 'enabled' => 1, 'visible' => -2, 'position' => 50, 'searchall' => 1),
137
        'town' => array('type' => 'varchar(50)', 'label' => 'Town', 'enabled' => 1, 'visible' => -2, 'position' => 55, 'searchall' => 1),
138
        'fk_departement' => array('type' => 'integer', 'label' => 'State', 'enabled' => 1, 'visible' => 0, 'position' => 60),
139
        'fk_pays' => array('type' => 'integer:Ccountry:core/class/ccountry.class.php', 'label' => 'Country', 'enabled' => 1, 'visible' => -1, 'position' => 65),
140
        'phone' => array('type' => 'varchar(20)', 'label' => 'Phone', 'enabled' => 1, 'visible' => -2, 'position' => 70, 'searchall' => 1),
141
        'fax' => array('type' => 'varchar(20)', 'label' => 'Fax', 'enabled' => 1, 'visible' => -2, 'position' => 75, 'searchall' => 1),
142
        //'fk_user_author' =>array('type'=>'integer', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-2, 'position'=>82),
143
        'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'position' => 300),
144
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 301),
145
        'warehouse_usage' => array('type' => 'integer', 'label' => 'WarehouseUsage', 'enabled' => 'getDolGlobalInt("MAIN_FEATURES_LEVEL")', 'visible' => 1, 'position' => 400, 'arrayofkeyval' => array(1 => 'InternalWarehouse', 2 => 'ExternalWarehouse')),
146
        //'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000),
147
        //'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPDF', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
148
        'statut' => array('type' => 'tinyint(4)', 'label' => 'Status', 'enabled' => 1, 'visible' => 1, 'position' => 500, 'css' => 'minwidth50'),
149
    );
150
151
    /**
152
     * Warehouse closed, inactive
153
     */
154
    const STATUS_CLOSED = 0;
155
156
    /**
157
     * Warehouse open and any operations are allowed (customer shipping, supplier dispatch, internal stock transfers/corrections).
158
     */
159
    const STATUS_OPEN_ALL = 1;
160
161
    /**
162
     * Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping and supplier dispatch).
163
     */
164
    const STATUS_OPEN_INTERNAL = 2;
165
166
    /**
167
     * Warehouse open and any operations are allowed, but warehouse is not included into calculation of stock.
168
     */
169
    const STATUS_OPENEXT_ALL = 3;   // TODO Implement this
170
171
172
173
    /**
174
     *  Constructor
175
     *
176
     *  @param      DoliDB      $db      Database handler
177
     */
178
    public function __construct($db)
179
    {
180
        $this->db = $db;
181
182
        $this->labelStatus[self::STATUS_CLOSED] = 'Closed2';
183
        if (getDolGlobalString('ENTREPOT_EXTRA_STATUS')) {
184
            $this->labelStatus[self::STATUS_OPEN_ALL] = 'OpenAnyMovement';
185
            $this->labelStatus[self::STATUS_OPEN_INTERNAL] = 'OpenInternal';
186
        } else {
187
            $this->labelStatus[self::STATUS_OPEN_ALL] = 'Opened';
188
        }
189
    }
190
191
    /**
192
     *  Creation d'un entrepot en base
193
     *
194
     *  @param      User    $user       Object user that create the warehouse
195
     *  @param      int     $notrigger  0=launch triggers after, 1=disable triggers
196
     *  @return     int                 Return >0 if OK, =<0 if KO
197
     */
198
    public function create($user, $notrigger = 0)
199
    {
200
        global $conf;
201
202
        $error = 0;
203
204
        $this->label = trim($this->label);
205
206
        // Error if label not defined
207
        if ($this->label == '') {
208
            $this->error = "ErrorFieldRequired";
209
            return 0;
210
        }
211
212
        $now = dol_now();
213
214
        $this->db->begin();
215
216
        $sql = "INSERT INTO " . $this->db->prefix() . "entrepot (ref, entity, datec, fk_user_author, fk_parent, fk_project)";
217
        $sql .= " VALUES ('" . $this->db->escape($this->label) . "', " . ((int) $conf->entity) . ", '" . $this->db->idate($now) . "', " . ((int) $user->id) . ", " . ($this->fk_parent > 0 ? ((int) $this->fk_parent) : "NULL") . ", " . ($this->fk_project > 0 ? ((int) $this->fk_project) : "NULL") . ")";
218
219
        dol_syslog(get_class($this) . "::create", LOG_DEBUG);
220
        $result = $this->db->query($sql);
221
        if ($result) {
222
            $id = $this->db->last_insert_id($this->db->prefix() . "entrepot");
223
            if ($id > 0) {
224
                $this->id = $id;
225
226
                if (!$error) {
227
                    $result = $this->update($id, $user);
228
                    if ($result <= 0) {
229
                        $error++;
230
                    }
231
                }
232
233
                // Actions on extra fields
234
                if (!$error) {
235
                    $result = $this->insertExtraFields();
236
                    if ($result < 0) {
237
                        $error++;
238
                    }
239
                }
240
241
                if (!$error && !$notrigger) {
242
                    // Call triggers
243
                    $result = $this->call_trigger('WAREHOUSE_CREATE', $user);
244
                    if ($result < 0) {
245
                        $error++;
246
                    }
247
                    // End call triggers
248
                }
249
250
                if (!$error) {
251
                    $this->db->commit();
252
                    return $id;
253
                } else {
254
                    dol_syslog(get_class($this) . "::create return -3");
255
                    $this->db->rollback();
256
                    return -3;
257
                }
258
            } else {
259
                $this->error = "Failed to get insert id";
260
                dol_syslog(get_class($this) . "::create return -2");
261
                return -2;
262
            }
263
        } else {
264
            $this->error = $this->db->error();
265
            dol_syslog(get_class($this) . "::create Error " . $this->db->error());
266
            $this->db->rollback();
267
            return -1;
268
        }
269
    }
270
271
    /**
272
     *  Update properties of a warehouse
273
     *
274
     *  @param      int     $id         id of warehouse to modify
275
     *  @param      User    $user       User object
276
     *  @param      int     $notrigger  0=launch triggers after, 1=disable trigge
277
     *  @return     int                 Return >0 if OK, <0 if KO
278
     */
279
    public function update($id, $user, $notrigger = 0)
280
    {
281
        global $conf;
282
283
        $error = 0;
284
285
        if (empty($id)) {
286
            $id = $this->id;
287
        }
288
289
        // Check if new parent is already a child of current warehouse
290
        if (!empty($this->fk_parent)) {
291
            $TChildWarehouses = array($id);
292
            $TChildWarehouses = $this->get_children_warehouses($this->id, $TChildWarehouses);
293
            if (in_array($this->fk_parent, $TChildWarehouses)) {
294
                $this->error = 'ErrorCannotAddThisParentWarehouse';
295
                return -2;
296
            }
297
        }
298
299
        $this->label = trim($this->label);
300
301
        $this->description = trim($this->description);
302
303
        $this->lieu = trim($this->lieu);
304
305
        $this->address = trim($this->address);
306
        $this->zip = trim($this->zip);
307
        $this->town = trim($this->town);
308
        $this->country_id = ($this->country_id > 0 ? $this->country_id : 0);
309
310
        $sql = "UPDATE " . $this->db->prefix() . "entrepot";
311
        $sql .= " SET ref = '" . $this->db->escape($this->label) . "'";
312
        $sql .= ", fk_parent = " . (($this->fk_parent > 0) ? $this->fk_parent : "NULL");
313
        $sql .= ", fk_project = " . (($this->fk_project > 0) ? $this->fk_project : "NULL");
314
        $sql .= ", description = '" . $this->db->escape($this->description) . "'";
315
        $sql .= ", statut = " . ((int) $this->statut);
316
        $sql .= ", lieu = '" . $this->db->escape($this->lieu) . "'";
317
        $sql .= ", address = '" . $this->db->escape($this->address) . "'";
318
        $sql .= ", zip = '" . $this->db->escape($this->zip) . "'";
319
        $sql .= ", town = '" . $this->db->escape($this->town) . "'";
320
        $sql .= ", fk_pays = " . ((int) $this->country_id);
321
        $sql .= ", phone = '" . $this->db->escape($this->phone) . "'";
322
        $sql .= ", fax = '" . $this->db->escape($this->fax) . "'";
323
        $sql .= " WHERE rowid = " . ((int) $id);
324
325
        $this->db->begin();
326
327
        dol_syslog(get_class($this) . "::update", LOG_DEBUG);
328
        $resql = $this->db->query($sql);
329
330
        if (!$resql) {
331
            $error++;
332
            $this->errors[] = "Error " . $this->db->lasterror();
333
        }
334
335
        if (!$error) {
336
            $result = $this->insertExtraFields();
337
            if ($result < 0) {
338
                $error++;
339
            }
340
        }
341
342
        if (!$error && !$notrigger) {
343
            // Call triggers
344
            $result = $this->call_trigger('WAREHOUSE_MODIFY', $user);
345
            if ($result < 0) {
346
                $error++;
347
            }
348
            // End call triggers
349
        }
350
351
        if (!$error) {
352
            $this->db->commit();
353
            return 1;
354
        } else {
355
            $this->db->rollback();
356
            $this->error = $this->db->lasterror();
357
            return -1;
358
        }
359
    }
360
361
362
    /**
363
     *  Delete a warehouse
364
     *
365
     *  @param      User    $user          Object user that made deletion
366
     *  @param      int     $notrigger     1=No trigger
367
     *  @return     int                    Return integer <0 if KO, >0 if OK
368
     */
369
    public function delete($user, $notrigger = 0)
370
    {
371
        global $conf;
372
373
        $error = 0;
374
375
        dol_syslog(get_class($this) . "::delete id=" . $this->id, LOG_DEBUG);
376
377
        $this->db->begin();
378
379
        if (!$error && empty($notrigger)) {
380
            // Call trigger
381
            $result = $this->call_trigger('WAREHOUSE_DELETE', $user);
382
            if ($result < 0) {
383
                $error++;
384
            }
385
            // End call triggers
386
        }
387
388
        if (!$error) {
389
            $sql = "DELETE FROM " . $this->db->prefix() . "product_batch";
390
            $sql .= " WHERE fk_product_stock IN (SELECT rowid FROM " . $this->db->prefix() . "product_stock as ps WHERE ps.fk_entrepot = " . ((int) $this->id) . ")";
391
            $result = $this->db->query($sql);
392
            if (!$result) {
393
                $error++;
394
                $this->errors[] = $this->db->lasterror();
395
            }
396
        }
397
398
        if (!$error) {
399
            $elements = array('stock_mouvement', 'product_stock');
400
            foreach ($elements as $table) {
401
                if (!$error) {
402
                    $sql = "DELETE FROM " . $this->db->prefix() . $table;
403
                    $sql .= " WHERE fk_entrepot = " . ((int) $this->id);
404
405
                    $result = $this->db->query($sql);
406
                    if (!$result) {
407
                        $error++;
408
                        $this->errors[] = $this->db->lasterror();
409
                    }
410
                }
411
            }
412
        }
413
414
        // Removed extrafields
415
        if (!$error) {
416
            if (!$error) {
417
                $result = $this->deleteExtraFields();
418
                if ($result < 0) {
419
                    $error++;
420
                    dol_syslog(get_class($this) . "::delete Error " . $this->error, LOG_ERR);
421
                }
422
            }
423
        }
424
425
        if (!$error) {
426
            $sql = "DELETE FROM " . $this->db->prefix() . "entrepot";
427
            $sql .= " WHERE rowid = " . ((int) $this->id);
428
            $resql1 = $this->db->query($sql);
429
            if (!$resql1) {
430
                $error++;
431
                $this->errors[] = $this->db->lasterror();
432
                dol_syslog(get_class($this) . "::delete Error " . $this->db->lasterror(), LOG_ERR);
433
            }
434
        }
435
436
        if (!$error) {
437
            // Update denormalized fields because we change content of produt_stock. Warning: Do not use "SET p.stock", does not works with pgsql
438
            $sql = "UPDATE " . $this->db->prefix() . "product as p SET stock = (SELECT SUM(ps.reel) FROM " . $this->db->prefix() . "product_stock as ps WHERE ps.fk_product = p.rowid)";
439
            $resql2 = $this->db->query($sql);
440
            if (!$resql2) {
441
                $error++;
442
                $this->errors[] = $this->db->lasterror();
443
                dol_syslog(get_class($this) . "::delete Error " . $this->db->lasterror(), LOG_ERR);
444
            }
445
        }
446
447
        if (!$error) {
448
            $this->db->commit();
449
            return 1;
450
        } else {
451
            $this->db->rollback();
452
            return -1;
453
        }
454
    }
455
456
457
    /**
458
     *  Load warehouse data
459
     *
460
     *  @param      int     $id     Warehouse id
461
     *  @param      string  $ref    Warehouse label
462
     *  @return     int             >0 if OK, <0 if KO
463
     */
464
    public function fetch($id, $ref = '')
465
    {
466
        global $conf;
467
468
        dol_syslog(get_class($this) . "::fetch id=" . $id . " ref=" . $ref);
469
470
        // Check parameters
471
        if (!$id && !$ref) {
472
            $this->error = 'ErrorWrongParameters';
473
            dol_syslog(get_class($this) . "::fetch " . $this->error);
474
            return -1;
475
        }
476
477
        $sql  = "SELECT rowid, entity, fk_parent, fk_project, ref as label, description, statut, lieu, address, zip, town, fk_pays as country_id, phone, fax,";
478
        $sql .= " model_pdf, import_key";
479
        $sql .= " FROM " . $this->db->prefix() . "entrepot";
480
        if ($id) {
481
            $sql .= " WHERE rowid = " . ((int) $id);
482
        } else {
483
            $sql .= " WHERE entity IN (" . getEntity('stock') . ")";
484
            if ($ref) {
485
                $sql .= " AND ref = '" . $this->db->escape($ref) . "'";
486
            }
487
        }
488
489
        $result = $this->db->query($sql);
490
        if ($result) {
491
            if ($this->db->num_rows($result) > 0) {
492
                $obj = $this->db->fetch_object($result);
493
494
                $this->id             = $obj->rowid;
495
                $this->entity         = $obj->entity;
496
                $this->fk_parent      = $obj->fk_parent;
497
                $this->fk_project     = $obj->fk_project;
498
                $this->ref            = $obj->label;
499
                $this->label          = $obj->label;
500
                $this->description    = $obj->description;
501
                $this->statut         = $obj->statut;
502
                $this->lieu           = $obj->lieu;
503
                $this->address        = $obj->address;
504
                $this->zip            = $obj->zip;
505
                $this->town           = $obj->town;
506
                $this->country_id     = $obj->country_id;
507
                $this->phone          = $obj->phone;
508
                $this->fax            = $obj->fax;
509
510
                $this->model_pdf      = $obj->model_pdf;
511
                $this->import_key     = $obj->import_key;
512
513
                // Retrieve all extrafield
514
                // fetch optionals attributes and labels
515
                $this->fetch_optionals();
516
517
                include_once BASE_PATH . '/../Dolibarr/Lib/Company.php';
518
                $tmp = getCountry($this->country_id, 'all');
519
                $this->country = $tmp['label'];
520
                $this->country_code = $tmp['code'];
521
522
                return 1;
523
            } else {
524
                $this->error = "Record Not Found";
525
                return 0;
526
            }
527
        } else {
528
            $this->error = $this->db->error();
529
            return -1;
530
        }
531
    }
532
533
534
    /**
535
     *  Load warehouse info data
536
     *
537
     *  @param  int     $id      warehouse id
538
     *  @return void
539
     */
540
    public function info($id)
541
    {
542
        $sql = "SELECT e.rowid, e.datec, e.tms as datem, e.fk_user_author";
543
        $sql .= " FROM " . $this->db->prefix() . "entrepot as e";
544
        $sql .= " WHERE e.rowid = " . ((int) $id);
545
546
        dol_syslog(get_class($this) . "::info", LOG_DEBUG);
547
        $result = $this->db->query($sql);
548
        if ($result) {
549
            if ($this->db->num_rows($result)) {
550
                $obj = $this->db->fetch_object($result);
551
552
                $this->id = $obj->rowid;
553
554
                $this->user_creation_id = $obj->fk_user_author;
555
                $this->date_creation     = $this->db->jdate($obj->datec);
556
                $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
557
            }
558
559
            $this->db->free($result);
560
        } else {
561
            dol_print_error($this->db);
562
        }
563
    }
564
565
566
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
567
    /**
568
     *  Return list of all warehouses
569
     *
570
     *  @param  int     $status     Status
571
     *  @return array               Array list of warehouses
572
     */
573
    public function list_array($status = 1)
574
    {
575
		// phpcs:enable
576
        $liste = array();
577
578
        $sql = "SELECT rowid, ref as label";
579
        $sql .= " FROM " . $this->db->prefix() . "entrepot";
580
        $sql .= " WHERE entity IN (" . getEntity('stock') . ")";
581
        $sql .= " AND statut = " . ((int) $status);
582
583
        $result = $this->db->query($sql);
584
        $i = 0;
585
        $num = $this->db->num_rows($result);
586
        if ($result) {
587
            while ($i < $num) {
588
                $row = $this->db->fetch_row($result);
589
                $liste[$row[0]] = $row[1];
590
                $i++;
591
            }
592
            $this->db->free($result);
593
        }
594
        return $liste;
595
    }
596
597
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
598
    /**
599
     *  Return number of unique different product into a warehouse
600
     *
601
     *  @return     array|int       Array('nb'=>Nb, 'value'=>Value)
602
     */
603
    public function nb_different_products()
604
    {
605
		// phpcs:enable
606
        $ret = array();
607
608
        $sql = "SELECT count(distinct p.rowid) as nb";
609
        $sql .= " FROM " . $this->db->prefix() . "product_stock as ps";
610
        $sql .= ", " . $this->db->prefix() . "product as p";
611
        $sql .= " WHERE ps.fk_entrepot = " . ((int) $this->id);
612
        $sql .= " AND ps.fk_product = p.rowid";
613
614
        //print $sql;
615
        $result = $this->db->query($sql);
616
        if ($result) {
617
            $obj = $this->db->fetch_object($result);
618
            $ret['nb'] = $obj->nb;
619
            $this->db->free($result);
620
        } else {
621
            $this->error = $this->db->lasterror();
622
            return -1;
623
        }
624
625
        return $ret;
626
    }
627
628
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
629
    /**
630
     *  Return stock and value of warehosue
631
     *
632
     *  @return     array|int       Array('nb'=>Nb, 'value'=>Value)
633
     */
634
    public function nb_products()
635
    {
636
        global $conf;
637
		// phpcs:enable
638
        $ret = array();
639
640
        //For MultiCompany PMP per entity
641
        $separatedPMP = false;
642
        if (getDolGlobalString('MULTICOMPANY_PRODUCT_SHARING_ENABLED') && getDolGlobalString('MULTICOMPANY_PMP_PER_ENTITY_ENABLED')) {
643
            $separatedPMP = true;
644
        }
645
646
        if ($separatedPMP) {
647
            $sql = "SELECT sum(ps.reel) as nb, sum(ps.reel * pa.pmp) as value";
648
        } else {
649
            $sql = "SELECT sum(ps.reel) as nb, sum(ps.reel * p.pmp) as value";
650
        }
651
        $sql .= " FROM " . $this->db->prefix() . "product_stock as ps";
652
        $sql .= ", " . $this->db->prefix() . "product as p";
653
        if ($separatedPMP) {
654
            $sql .= ", " . $this->db->prefix() . "product_perentity as pa";
655
        }
656
        $sql .= " WHERE ps.fk_entrepot = " . ((int) $this->id);
657
        if ($separatedPMP) {
658
            $sql .= " AND pa.fk_product = p.rowid AND pa.entity = " . (int) $conf->entity;
659
        }
660
        $sql .= " AND ps.fk_product = p.rowid";
661
        //print $sql;
662
        $result = $this->db->query($sql);
663
        if ($result) {
664
            $obj = $this->db->fetch_object($result);
665
            $ret['nb'] = $obj->nb;
666
            $ret['value'] = $obj->value;
667
            $this->db->free($result);
668
        } else {
669
            $this->error = $this->db->lasterror();
670
            return -1;
671
        }
672
673
        return $ret;
674
    }
675
676
    /**
677
     *  Return label of status of object
678
     *
679
     *  @param      int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
680
     *  @return     string              Label of status
681
     */
682
    public function getLibStatut($mode = 0)
683
    {
684
        return $this->LibStatut($this->statut, $mode);
685
    }
686
687
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
688
    /**
689
     *  Return label of a given status
690
     *
691
     *  @param  int     $status     Id status
692
     *  @param  int     $mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
693
     *  @return string              Label of status
694
     */
695
    public function LibStatut($status, $mode = 0)
696
    {
697
		// phpcs:enable
698
        global $langs;
699
700
        $statusType = 'status5';
701
        if ($status > 0) {
702
            $statusType = 'status4';
703
        }
704
705
        $langs->load('stocks');
706
        $label = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
707
        $labelshort = $langs->transnoentitiesnoconv($this->labelStatus[$status]);
708
709
        return dolGetStatus($label, $labelshort, '', $statusType, $mode);
710
    }
711
712
    /**
713
     * getTooltipContentArray
714
     *
715
     * @param   array   $params     Params to construct tooltip data
716
     * @since   v18
717
     * @return  array
718
     */
719
    public function getTooltipContentArray($params)
720
    {
721
        global $conf, $langs, $user;
722
723
        $langs->load('stocks');
724
725
        $datas = [];
726
727
        $option = $params['option'] ?? '';
728
        $nofetch = !empty($params['nofetch']);
729
730
        if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
731
            return ['optimize' => $langs->trans("Warehouse")];
732
        }
733
        $datas['picto'] = img_picto('', $this->picto) . ' <u class="paddingrightonly">' . $langs->trans("Warehouse") . '</u>';
734
        if (isset($this->statut)) {
735
            $datas['picto'] .= ' ' . $this->getLibStatut(5);
736
        }
737
        $datas['ref'] = '<br><b>' . $langs->trans('Ref') . ':</b> ' . (empty($this->ref) ? $this->label : $this->ref);
738
        if (!empty($this->lieu)) {
739
            $datas['locationsummary'] = '<br><b>' . $langs->trans('LocationSummary') . ':</b> ' . $this->lieu;
740
        }
741
        // show categories for this record only in ajax to not overload lists
742
        if (!$nofetch && isModEnabled('category')) {
743
            $form = new Form($this->db);
744
            $datas['categories_warehouse'] = '<br>' . $form->showCategories($this->id, Categorie::TYPE_WAREHOUSE, 1, 1);
745
        }
746
747
        return $datas;
748
    }
749
750
    /**
751
     *  Return clickable name (possibility with the pictogram)
752
     *
753
     *  @param      int     $withpicto              with pictogram
754
     *  @param      string  $option                 Where the link point to
755
     *  @param      int     $showfullpath           0=Show ref only. 1=Show full path instead of Ref (this->fk_parent must be defined)
756
     *  @param      int     $notooltip              1=Disable tooltip
757
     *  @param      string  $morecss                Add more css on link
758
     *  @param      int     $save_lastsearch_value  -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
759
     *  @return     string                          String with URL
760
     */
761
    public function getNomUrl($withpicto = 0, $option = '', $showfullpath = 0, $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
762
    {
763
        global $conf, $langs, $hookmanager;
764
        $langs->load("stocks");
765
766
        if (!empty($conf->dol_no_mouse_hover)) {
767
            $notooltip = 1; // Force disable tooltips
768
        }
769
770
        if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
771
            $withpicto = 0;
772
        }
773
774
        $result = '';
775
        $params = [
776
            'id' => $this->id,
777
            'objecttype' => $this->element,
778
            'option' => $option,
779
            'nofetch' => 1,
780
        ];
781
        $classfortooltip = 'classfortooltip';
782
        $dataparams = '';
783
        if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
784
            $classfortooltip = 'classforajaxtooltip';
785
            $dataparams = ' data-params="' . dol_escape_htmltag(json_encode($params)) . '"';
786
            $label = 'ToComplete';
787
        } else {
788
            $label = implode($this->getTooltipContentArray($params));
789
        }
790
791
        $url = DOL_URL_ROOT . '/product/stock/card.php?id=' . $this->id;
792
793
        if ($option != 'nolink') {
794
            // Add param to save lastsearch_values or not
795
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
796
            if ($save_lastsearch_value == -1 && isset($_SERVER['PHP_SELF']) && preg_match('/list\.php/', $_SERVER['PHP_SELF'])) {
797
                $add_save_lastsearch_values = 1;
798
            }
799
            if ($add_save_lastsearch_values) {
800
                $url .= '&save_lastsearch_values=1';
801
            }
802
        }
803
804
        $linkclose = '';
805
        if (empty($notooltip)) {
806
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
807
                $label = $langs->trans("Warehouse");
808
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
809
            }
810
            $linkclose .= ($label ? ' title="' . dol_escape_htmltag($label, 1) . '"' : ' title="tocomplete"');
811
            $linkclose .= $dataparams . ' class="' . $classfortooltip . '"';
812
        }
813
814
        $linkstart = '<a href="' . $url . '"';
815
        $linkstart .= $linkclose . '>';
816
        $linkend = '</a>';
817
818
        $result .= $linkstart;
819
        if ($withpicto) {
820
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . '"'), 0, 0, $notooltip ? 0 : 1);
821
        }
822
        if ($withpicto != 2) {
823
            $result .= (($showfullpath || getDolGlobalString('STOCK_ALWAYS_SHOW_FULL_ARBO')) ? $this->get_full_arbo() : $this->label);
824
        }
825
        $result .= $linkend;
826
827
        global $action;
828
        $hookmanager->initHooks(array('warehousedao'));
829
        $parameters = array('id' => $this->id, 'getnomurl' => &$result, 'withpicto' => $withpicto, 'option' => $option, 'showfullpath' => $showfullpath, 'notooltip' => $notooltip);
830
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
831
        if ($reshook > 0) {
832
            $result = $hookmanager->resPrint;
833
        } else {
834
            $result .= $hookmanager->resPrint;
835
        }
836
837
        return $result;
838
    }
839
840
    /**
841
     *  Initialise an instance with random values.
842
     *  Used to build previews or test instances.
843
     *  id must be 0 if object instance is a specimen.
844
     *
845
     *  @return int
846
     */
847
    public function initAsSpecimen()
848
    {
849
        global $user, $langs, $conf, $mysoc;
850
851
        $now = dol_now();
852
853
        // Initialize parameters
854
        $this->id = 0;
855
        $this->label = 'WAREHOUSE SPECIMEN';
856
        $this->description = 'WAREHOUSE SPECIMEN ' . dol_print_date($now, 'dayhourlog');
857
        $this->statut = 1;
858
        $this->specimen = 1;
859
860
        $this->lieu = 'Location test';
861
        $this->address = '21 jump street';
862
        $this->zip = '99999';
863
        $this->town = 'MyTown';
864
        $this->country_id = 1;
865
        $this->country_code = 'FR';
866
867
        return 1;
868
    }
869
870
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
871
    /**
872
     *  Return full path to current warehouse
873
     *
874
     *  @return     string  String full path to current warehouse separated by " >> "
875
     */
876
    public function get_full_arbo()
877
    {
878
		// phpcs:enable
879
        global $user, $langs, $conf;
880
881
        $TArbo = array($this->label);
882
883
        $protection = 100; // We limit depth of warehouses to 100
884
885
        $warehousetmp = new Entrepot($this->db);
886
887
        $parentid = $this->fk_parent; // If parent_id not defined on current object, we do not start consecutive searches of parents
888
        $i = 0;
889
        while ($parentid > 0 && $i < $protection) {
890
            $sql = "SELECT fk_parent FROM " . $this->db->prefix() . "entrepot WHERE rowid = " . ((int) $parentid);
891
            $resql = $this->db->query($sql);
892
            if ($resql) {
893
                $objarbo = $this->db->fetch_object($resql);
894
                if ($objarbo) {
895
                    $warehousetmp->fetch($parentid);
896
                    $TArbo[] = $warehousetmp->label;
897
                    $parentid = $objarbo->fk_parent;
898
                } else {
899
                    break;
900
                }
901
            } else {
902
                dol_print_error($this->db);
903
            }
904
905
            $i++;
906
        }
907
908
        return implode(' >> ', array_reverse($TArbo));
909
    }
910
911
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
912
    /**
913
     * Return array of children warehouses ids from $id warehouse (recursive function)
914
     *
915
     * @param   int         $id                 id parent warehouse
916
     * @param   integer[]   $TChildWarehouses   array which will contain all children (param by reference)
917
     * @return  integer[]   $TChildWarehouses   array which will contain all children
918
     */
919
    public function get_children_warehouses($id, &$TChildWarehouses)
920
    {
921
		// phpcs:enable
922
923
        $sql = "SELECT rowid
924
				FROM " . $this->db->prefix() . "entrepot
925
				WHERE fk_parent = " . ((int) $id);
926
927
        $resql = $this->db->query($sql);
928
        if ($resql) {
929
            while ($res = $this->db->fetch_object($resql)) {
930
                $TChildWarehouses[] = $res->rowid;
931
                $this->get_children_warehouses($res->rowid, $TChildWarehouses);
932
            }
933
        }
934
935
        return $TChildWarehouses;
936
    }
937
938
    /**
939
     *  Create object on disk
940
     *
941
     *  @param     string       $modele         force le modele a utiliser ('' to not force)
942
     *  @param     Translate    $outputlangs    Object langs to use for output
943
     *  @param     int          $hidedetails    Hide details of lines
944
     *  @param     int          $hidedesc       Hide description
945
     *  @param     int          $hideref        Hide ref
946
     *  @return    int                          0 if KO, 1 if OK
947
     */
948
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0)
949
    {
950
        global $conf, $user, $langs;
951
952
        $langs->load("stocks");
953
        $outputlangs->load("products");
954
955
        if (!dol_strlen($modele)) {
956
            $modele = 'standard';
957
958
            if ($this->model_pdf) {
959
                $modele = $this->model_pdf;
960
            } elseif (getDolGlobalString('STOCK_ADDON_PDF')) {
961
                $modele = getDolGlobalString('STOCK_ADDON_PDF');
962
            }
963
        }
964
965
        $modelpath = "core/modules/stock/doc/";
966
967
        return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
968
    }
969
970
    /**
971
     * Sets object to supplied categories.
972
     *
973
     * Deletes object from existing categories not supplied.
974
     * Adds it to non existing supplied categories.
975
     * Existing categories are left untouch.
976
     *
977
     * @param   int[]|int   $categories     Category or categories IDs
978
     * @return  int                         Return integer <0 if KO, >0 if OK
979
     */
980
    public function setCategories($categories)
981
    {
982
        return parent::setCategoriesCommon($categories, Categorie::TYPE_WAREHOUSE);
983
    }
984
985
    /**
986
     *  Return clicable link of object (with eventually picto)
987
     *
988
     *  @param      string      $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
989
     *  @param      array       $arraydata              Array of data
990
     *  @return     string                              HTML Code for Kanban thumb.
991
     */
992
    public function getKanbanView($option = '', $arraydata = null)
993
    {
994
        $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
995
996
        $return = '<div class="box-flex-item box-flex-grow-zero">';
997
        $return .= '<div class="info-box info-box-sm">';
998
        $return .= '<div class="info-box-icon bg-infobox-action" >';
999
        $return .= img_picto('', $this->picto);
1000
        $return .= '</div>';
1001
        $return .= '<div class="info-box-content" >';
1002
        $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . (method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref) . '</span>';
1003
        if ($selected >= 0) {
1004
            $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
1005
        }
1006
        if (property_exists($this, 'lieu') && (!empty($this->lieu))) {
1007
            $return .= '<br><span class="info-box-label opacitymedium">' . $this->lieu . '</span>';
1008
        }
1009
        if (property_exists($this, 'sellvalue') && $this->sellvalue != 0) {
1010
            $return .= '<br><span class="info-box-label amount">' . price($this->sellvalue) . '</span>';
1011
        }
1012
        if (method_exists($this, 'getLibStatut')) {
1013
            $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
1014
        }
1015
        $return .= '</div>';
1016
        $return .= '</div>';
1017
        $return .= '</div>';
1018
        return $return;
1019
    }
1020
}
1021