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

Inventory::LibStatut()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
nc 2
nop 2
dl 0
loc 22
rs 9.7666
c 0
b 0
f 0
1
<?php
2
3
/* Copyright (C) 2007-2019  Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2014-2016  Juanjo Menent               <[email protected]>
5
 * Copyright (C) 2015       Florian Henry               <[email protected]>
6
 * Copyright (C) 2015       Raphaël Doursenaud          <[email protected]>
7
 * Copyright (C) 2024       Frédéric France             <[email protected]>
8
 * Copyright (C) 2024		MDW							<[email protected]>
9
 * Copyright (C) 2024       Rafael San José             <[email protected]>
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23
 */
24
25
namespace Dolibarr\Code\Product\Classes;
26
27
use Dolibarr\Core\Base\CommonObject;
28
use DoliDB;
29
30
/**
31
 * \file        product/inventory/class/inventory.class.php
32
 * \ingroup     inventory
33
 * \brief       This file is a CRUD class file for Inventory (Create/Read/Update/Delete)
34
 */
35
36
//use Dolibarr\Code\Societe\Classes\Societe;
37
//
38
/**
39
 * Class for Inventory
40
 */
41
42
class Inventory extends CommonObject
43
{
44
    /**
45
     * @var string ID to identify managed object
46
     */
47
    public $element = 'inventory';
48
49
    /**
50
     * @var string Name of table without prefix where object is stored
51
     */
52
    public $table_element = 'inventory';
53
54
    /**
55
     * @var string String with name of icon for inventory
56
     */
57
    public $picto = 'inventory';
58
59
    const STATUS_DRAFT     = 0;     // Draft
60
    const STATUS_VALIDATED = 1;     // Inventory is in process
61
    const STATUS_RECORDED  = 2;     // Inventory is finisged. Stock movement has been recorded.
62
    const STATUS_CANCELED  = 9;     // Canceled
63
64
    /**
65
     *  'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
66
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
67
     *  'label' the translation key.
68
     *  'picto' is code of a picto to show before value in forms
69
     *  'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalString("MY_SETUP_PARAM")'
70
     *  'position' is the sort order of field.
71
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
72
     *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
73
     *  'noteditable' says if field is not editable (1 or 0)
74
     *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
75
     *  'index' if we want an index in database.
76
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
77
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
78
     *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
79
     *  'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'maxwidth200', 'wordbreak', 'tdoverflowmax200', 'minwidth300 maxwidth500 widthcentpercentminusx'
80
     *  'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
81
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
82
     *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
83
     *  'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar'
84
     *  'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
85
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
86
     *
87
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
88
     */
89
90
    // BEGIN MODULEBUILDER PROPERTIES
91
    /**
92
     * @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...
93
     */
94
    public $fields = array(
95
        'rowid'              => array('type' => 'integer', 'label' => 'TechnicalID', 'visible' => -1, 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'index' => 1, 'comment' => 'Id',),
96
        'ref'                => array('type' => 'varchar(64)', 'label' => 'Ref', 'visible' => 1, 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'index' => 1, 'searchall' => 1, 'comment' => 'Reference of object', 'css' => 'maxwidth150'),
97
        'entity'             => array('type' => 'integer', 'label' => 'Entity', 'visible' => 0, 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'index' => 1,),
98
        'title'              => array('type' => 'varchar(255)', 'label' => 'Label', 'visible' => 1, 'enabled' => 1, 'position' => 25, 'css' => 'minwidth300', 'csslist' => 'tdoverflowmax150', 'alwayseditable' => 1),
99
        'fk_warehouse'       => array('type' => 'integer:Entrepot:product/stock/class/entrepot.class.php', 'label' => 'Warehouse', 'visible' => 1, 'enabled' => 1, 'position' => 30, 'index' => 1, 'help' => 'InventoryForASpecificWarehouse', 'picto' => 'stock', 'css' => 'minwidth300 maxwidth500 widthcentpercentminusx', 'csslist' => 'tdoverflowmax150'),
100
        'fk_product'         => array('type' => 'integer:Product:product/class/product.class.php', 'label' => 'Product', 'get_name_url_params' => '0::0:-1:0::1', 'visible' => 1, 'enabled' => 1, 'position' => 32, 'index' => 1, 'help' => 'InventoryForASpecificProduct', 'picto' => 'product', 'css' => 'minwidth300 maxwidth500 widthcentpercentminusx', 'csslist' => 'tdoverflowmax150'),
101
        'categories_product' => array('type' => 'chkbxlst:categorie:label:rowid::type=0:0:', 'label' => 'OrProductsWithCategories', 'visible' => 3, 'enabled' => 1, 'position' => 33, 'help' => '', 'picto' => 'category', 'css' => 'minwidth300 maxwidth500 widthcentpercentminusx'),
102
        'date_inventory'     => array('type' => 'date', 'label' => 'DateValue', 'visible' => 1, 'enabled' => '$conf->global->STOCK_INVENTORY_ADD_A_VALUE_DATE', 'position' => 35, 'csslist' => 'nowraponall'),  // This date is not used so disabled by default.
103
        'date_creation'      => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 500, 'csslist' => 'nowraponall'),
104
        'tms'                => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 501, 'csslist' => 'nowraponall'),
105
        'date_validation'    => array('type' => 'datetime', 'label' => 'DateValidation', 'visible' => -2, 'enabled' => 1, 'position' => 502, 'csslist' => 'nowraponall'),
106
        'fk_user_creat'      => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 510, 'foreignkey' => 'user.rowid', 'csslist' => 'tdoverflowmax150'),
107
        'fk_user_modif'      => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 511, 'csslist' => 'tdoverflowmax150'),
108
        'fk_user_valid'      => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'visible' => -2, 'enabled' => 1, 'position' => 512, 'csslist' => 'tdoverflowmax150'),
109
        'import_key'         => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'index' => 0, 'position' => 1000),
110
        'status'             => array('type' => 'integer', 'label' => 'Status', 'visible' => 4, 'enabled' => 1, 'position' => 1000, 'notnull' => 1, 'default' => '0', 'index' => 1, 'arrayofkeyval' => array(0 => 'Draft', 1 => 'Validated', 2 => 'Closed', 9 => 'Canceled'))
111
    );
112
113
    /**
114
     * @var int ID
115
     */
116
    public $rowid;
117
118
    /**
119
     * @var string Ref
120
     */
121
    public $ref;
122
123
    /**
124
     * @var int Entity
125
     */
126
    public $entity;
127
128
    /**
129
     * @var int ID
130
     */
131
    public $fk_warehouse;
132
133
    /**
134
     * @var int ID
135
     */
136
    public $fk_product;
137
138
    /**
139
     * @var string Categories id separated by comma
140
     */
141
    public $categories_product;
142
    public $date_inventory;
143
    public $title;
144
145
    /**
146
     * @var int Status
147
     */
148
    public $status;
149
150
    /**
151
     * @var integer|string date_creation
152
     */
153
    public $date_creation;
154
155
    /**
156
     * @var integer|string date_validation
157
     */
158
    public $date_validation;
159
160
    /**
161
     * @var int ID
162
     */
163
    public $fk_user_creat;
164
165
    /**
166
     * @var int ID
167
     */
168
    public $fk_user_modif;
169
170
    /**
171
     * @var int ID
172
     */
173
    public $fk_user_valid;
174
175
    /**
176
     * @var string import key
177
     */
178
    public $import_key;
179
    // END MODULEBUILDER PROPERTIES
180
181
182
183
    // If this object has a subtable with lines
184
185
    /**
186
     * @var string    Name of subtable line
187
     */
188
    public $table_element_line = 'inventorydet';
189
190
    /**
191
     * @var string    Field with ID of parent key if this field has a parent
192
     */
193
    public $fk_element = 'fk_inventory';
194
195
    /**
196
     * @var string    Name of subtable class that manage subtable lines
197
     */
198
    public $class_element_line = 'Inventoryline';
199
200
    /**
201
     * @var array<string, array<string>>    List of child tables. To test if we can delete object.
202
     */
203
    protected $childtables = array();
204
    /**
205
     * @var string[]    List of child tables. To know object to delete on cascade.
206
     */
207
    protected $childtablesoncascade = array('inventorydet');
208
209
    /**
210
     * @var InventoryLine[]     Array of subtable lines
211
     */
212
    public $lines = array();
213
214
215
216
    /**
217
     * Constructor
218
     *
219
     * @param DoliDB $db Database handler
220
     */
221
    public function __construct(DoliDB $db)
222
    {
223
        global $conf;
224
225
        $this->db = $db;
226
227
        $this->ismultientitymanaged = 1;
228
        $this->isextrafieldmanaged = 0;
229
230
        if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID')) {
231
            $this->fields['rowid']['visible'] = 0;
232
        }
233
        if (!isModEnabled('multicompany')) {
234
            $this->fields['entity']['enabled'] = 0;
235
        }
236
    }
237
238
239
    /**
240
     * Create object into database
241
     *
242
     * @param  User $user      User that creates
243
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
244
     * @return int             Return integer <0 if KO, Id of created object if OK
245
     */
246
    public function create(User $user, $notrigger = 0)
247
    {
248
        $result = $this->createCommon($user, $notrigger);
249
250
        return $result;
251
    }
252
253
    /**
254
     * Validate inventory (start it)
255
     *
256
     * @param   User    $user                   User that creates
257
     * @param   int     $notrigger              0=launch triggers after, 1=disable triggers
258
     * @param   int     $include_sub_warehouse  Include sub warehouses
259
     * @return  int                             Return integer <0 if KO, Id of created object if OK
260
     */
261
    public function validate(User $user, $notrigger = 0, $include_sub_warehouse = 0)
262
    {
263
        $this->db->begin();
264
265
        $result = 0;
266
267
        if ($this->status == self::STATUS_DRAFT) {
268
            // Delete inventory
269
            $sql = 'DELETE FROM ' . $this->db->prefix() . 'inventorydet WHERE fk_inventory = ' . ((int) $this->id);
270
            $resql = $this->db->query($sql);
271
            if (!$resql) {
272
                $this->error = $this->db->lasterror();
273
                $this->db->rollback();
274
                return -1;
275
            }
276
277
            // Scan existing stock to prefill the inventory
278
            $sql = "SELECT ps.rowid, ps.fk_entrepot as fk_warehouse, ps.fk_product, ps.reel,";
279
            if (isModEnabled('productbatch')) {
280
                $sql .= " pb.batch as batch, pb.qty as qty,";
281
            } else {
282
                $sql .= " '' as batch, 0 as qty,";
283
            }
284
            $sql .= " p.ref, p.tobatch";
285
            $sql .= " FROM " . $this->db->prefix() . "product_stock as ps";
286
            if (isModEnabled('productbatch')) {
287
                $sql .= " LEFT JOIN " . $this->db->prefix() . "product_batch as pb ON pb.fk_product_stock = ps.rowid";
288
            }
289
            $sql .= ", " . $this->db->prefix() . "product as p, " . $this->db->prefix() . "entrepot as e";
290
            $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
291
            $sql .= " AND ps.fk_product = p.rowid AND ps.fk_entrepot = e.rowid";
292
            if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
293
                $sql .= " AND p.fk_product_type = 0";
294
            }
295
            if ($this->fk_product > 0) {
296
                $sql .= " AND ps.fk_product = " . ((int) $this->fk_product);
297
            }
298
            if ($this->fk_warehouse > 0) {
299
                $sql .= " AND (ps.fk_entrepot = " . ((int) $this->fk_warehouse);
300
                if (!empty($include_sub_warehouse) && getDolGlobalInt('INVENTORY_INCLUDE_SUB_WAREHOUSE')) {
301
                    $TChildWarehouses = array();
302
                    $this->getChildWarehouse($this->fk_warehouse, $TChildWarehouses);
303
                    $sql .= " OR ps.fk_entrepot IN (" . $this->db->sanitize(implode(',', $TChildWarehouses)) . ")";
304
                }
305
                $sql .= ')';
306
            }
307
            if (!empty($this->categories_product)) {
308
                $sql .= " AND EXISTS (";
309
                $sql .= " SELECT cp.fk_product";
310
                $sql .= " FROM " . $this->db->prefix() . "categorie_product AS cp";
311
                $sql .= " WHERE cp.fk_product = ps.fk_product";
312
                $sql .= " AND cp.fk_categorie IN (" . $this->db->sanitize($this->categories_product) . ")";
313
                $sql .= ")";
314
            }
315
            if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
316
                $sql .= " AND NOT EXISTS (";
317
                $sql .= " SELECT pa.rowid";
318
                $sql .= " FROM " . $this->db->prefix() . "product_association as pa";
319
                $sql .= " WHERE pa.fk_product_pere = ps.fk_product";
320
                $sql .= ")";
321
            }
322
            $sql .= " ORDER BY p.rowid";
323
324
            $inventoryline = new InventoryLine($this->db);
325
326
            $resql = $this->db->query($sql);
327
            if ($resql) {
328
                $num = $this->db->num_rows($resql);
329
330
                $i = 0;
331
                while ($i < $num) {
332
                    $obj = $this->db->fetch_object($resql);
333
334
                    $inventoryline->fk_inventory = $this->id;
335
                    $inventoryline->fk_warehouse = $obj->fk_warehouse;
336
                    $inventoryline->fk_product = $obj->fk_product;
337
                    $inventoryline->batch = $obj->batch;
338
                    $inventoryline->datec = dol_now();
339
340
                    if (isModEnabled('productbatch')) {
341
                        if ($obj->batch && empty($obj->tobatch)) {
342
                            // Bad consistency of data. The product is not a product with lot/serial but we found a stock for some lot/serial.
343
                            $result = -2;
344
                            $this->error = 'The product ID=' . $obj->ref . " has stock with lot/serial but is configured to not manage lot/serial. You must first fix this, this way: Set the product to have 'Management of Lot/Serial' to Yes, then set it back to 'Management of Lot/Serial to No";
345
                            break;
346
                        }
347
348
                        $inventoryline->qty_stock = ($obj->batch ? $obj->qty : $obj->reel); // If there is batch detail, we take qty for batch, else global qty
349
                    } else {
350
                        $inventoryline->qty_stock = $obj->reel;
351
                    }
352
                    //var_dump($obj->batch.' '.$obj->qty.' '.$obj->reel.' '.$this->error);exit;
353
354
                    $resultline = $inventoryline->create($user);
355
                    if ($resultline <= 0) {
356
                        $this->error = $inventoryline->error;
357
                        $this->errors = $inventoryline->errors;
358
                        $result = -1;
359
                        break;
360
                    }
361
362
                    $i++;
363
                }
364
            } else {
365
                $result = -1;
366
                $this->error = $this->db->lasterror();
367
            }
368
        }
369
370
        if ($result >= 0) {
371
            $result = $this->setStatut($this::STATUS_VALIDATED, null, '', 'INVENTORY_VALIDATED');
372
        }
373
374
        if ($result > 0) {
375
            $this->db->commit();
376
        } else {
377
            $this->db->rollback();
378
        }
379
        return $result;
380
    }
381
382
    /**
383
     * Go back to draft
384
     *
385
     * @param  User $user      User that creates
386
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
387
     * @return int             Return integer <0 if KO, Id of created object if OK
388
     */
389
    public function setDraft(User $user, $notrigger = 0)
390
    {
391
        $this->db->begin();
392
393
        // Delete inventory
394
        $sql = 'DELETE FROM ' . $this->db->prefix() . 'inventorydet WHERE fk_inventory = ' . ((int) $this->id);
395
        $resql = $this->db->query($sql);
396
        if (!$resql) {
397
            $this->error = $this->db->lasterror();
398
            $this->db->rollback();
399
            return -1;
400
        }
401
402
        $result = $this->setStatut($this::STATUS_DRAFT, null, '', 'INVENTORY_DRAFT');
403
404
        if ($result > 0) {
405
            $this->db->commit();
406
        } else {
407
            $this->db->rollback();
408
        }
409
        return $result;
410
    }
411
412
    /**
413
     * Set to inventory to status "Closed". It means all stock movements were recorded.
414
     *
415
     * @param  User $user      User that creates
416
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
417
     * @return int             Return integer <0 if KO, Id of created object if OK
418
     */
419
    public function setRecorded(User $user, $notrigger = 0)
420
    {
421
        $this->db->begin();
422
423
        $result = $this->setStatut($this::STATUS_RECORDED, null, '', 'INVENTORY_RECORDED');
424
425
        if ($result > 0) {
426
            $this->db->commit();
427
        } else {
428
            $this->db->rollback();
429
            return -1;
430
        }
431
        return $result;
432
    }
433
434
    /**
435
     * Set to Canceled
436
     *
437
     * @param  User $user      User that creates
438
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
439
     * @return int             Return integer <0 if KO, Id of created object if OK
440
     */
441
    public function setCanceled(User $user, $notrigger = 0)
442
    {
443
        $this->db->begin();
444
445
        $result = $this->setStatut($this::STATUS_CANCELED, null, '', 'INVENTORY_CANCELED');
446
447
        if ($result > 0) {
448
            $this->db->commit();
449
        } else {
450
            $this->db->rollback();
451
            return -1;
452
        }
453
        return $result;
454
    }
455
456
    /**
457
     * Clone and object into another one
458
     *
459
     * @param   User    $user       User that creates
460
     * @param   int     $fromid     Id of object to clone
461
     * @return  mixed               New object created, <0 if KO
462
     */
463
    public function createFromClone(User $user, $fromid)
464
    {
465
        global $hookmanager, $langs;
466
        $error = 0;
467
468
        dol_syslog(__METHOD__, LOG_DEBUG);
469
470
        $object = new self($this->db);
471
472
        $this->db->begin();
473
474
        // Load source object
475
        $object->fetchCommon($fromid);
476
        // Reset some properties
477
        unset($object->id);
478
        unset($object->fk_user_creat);
479
        unset($object->import_key);
480
481
        // Clear fields
482
        $object->ref = "copy_of_" . $object->ref;
483
        $object->title = $langs->trans("CopyOf") . " " . $object->title;
484
        // ...
485
486
        // Create clone
487
        $object->context['createfromclone'] = 'createfromclone';
488
        $result = $object->createCommon($user);
489
        if ($result < 0) {
490
            $error++;
491
            $this->error = $object->error;
492
            $this->errors = $object->errors;
493
        }
494
495
        unset($object->context['createfromclone']);
496
497
        // End
498
        if (!$error) {
499
            $this->db->commit();
500
            return $object;
501
        } else {
502
            $this->db->rollback();
503
            return -1;
504
        }
505
    }
506
507
    /**
508
     * Load object in memory from the database
509
     *
510
     * @param int    $id   Id object
511
     * @param string $ref  Ref
512
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
513
     */
514
    public function fetch($id, $ref = null)
515
    {
516
        $result = $this->fetchCommon($id, $ref);
517
        //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
518
        return $result;
519
    }
520
521
    /**
522
     * Load object lines in memory from the database
523
     *
524
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
525
     */
526
    /*public function fetchLines()
527
     {
528
     $this->lines=array();
529
530
     // Load lines with object MyObjectLine
531
532
     return count($this->lines)?1:0;
533
     }*/
534
535
    /**
536
     * Update object into database
537
     *
538
     * @param  User $user      User that modifies
539
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
540
     * @return int             Return integer <0 if KO, >0 if OK
541
     */
542
    public function update(User $user, $notrigger = 0)
543
    {
544
        return $this->updateCommon($user, $notrigger);
545
    }
546
547
    /**
548
     * Delete object in database
549
     *
550
     * @param User  $user       User that deletes
551
     * @param int   $notrigger  0=launch triggers after, 1=disable triggers
552
     * @return int              Return integer <0 if KO, >0 if OK
553
     */
554
    public function delete(User $user, $notrigger = 0)
555
    {
556
        return $this->deleteCommon($user, $notrigger);
557
    }
558
559
    /**
560
     *  Delete a line of object in database
561
     *
562
     *  @param  User    $user       User that delete
563
     *  @param  int     $idline     Id of line to delete
564
     *  @param  int     $notrigger  0=launch triggers after, 1=disable triggers
565
     *  @return int                 >0 if OK, <0 if KO
566
     */
567
    public function deleteLine(User $user, $idline, $notrigger = 0)
568
    {
569
        if ($this->status < 0) {
570
            $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
571
            return -2;
572
        }
573
574
        return $this->deleteLineCommon($user, $idline, $notrigger);
575
    }
576
577
    /**
578
     *  Return a link to the object card (with optionally the picto)
579
     *
580
     *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
581
     *  @param  string  $option                     On what the link point to
582
     *  @param  int     $notooltip                  1=Disable tooltip
583
     *  @param  string  $morecss                    Add more css on link
584
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
585
     *  @return string                              String with URL
586
     */
587
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
588
    {
589
        global $db, $conf, $langs;
590
        global $dolibarr_main_authentication, $dolibarr_main_demo;
591
        global $menumanager;
592
593
        if (!empty($conf->dol_no_mouse_hover)) {
594
            $notooltip = 1; // Force disable tooltips
595
        }
596
597
        $result = '';
598
        $companylink = '';
599
600
        $label = '<u>' . $langs->trans("Inventory") . '</u>';
601
        $label .= '<br>';
602
        $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
603
604
        $url = dol_buildpath('/product/inventory/card.php', 1) . '?id=' . $this->id;
605
606
        $linkclose = '';
607
        if (empty($notooltip)) {
608
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
609
                $label = $langs->trans("ShowInventory");
610
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
611
            }
612
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
613
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
614
        } else {
615
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
616
        }
617
618
        $linkstart = '<a href="' . $url . '"';
619
        $linkstart .= $linkclose . '>';
620
        $linkend = '</a>';
621
622
        $result .= $linkstart;
623
        if ($withpicto) {
624
            $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
625
        }
626
        if ($withpicto != 2) {
627
            $result .= $this->ref;
628
        }
629
        $result .= $linkend;
630
        //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
631
632
        return $result;
633
    }
634
635
    /**
636
     *  Return the label of the status
637
     *
638
     *  @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
639
     *  @return string                 Label of status
640
     */
641
    public function getLibStatut($mode = 0)
642
    {
643
        return $this->LibStatut($this->status, $mode);
644
    }
645
646
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
647
    /**
648
     *  Return the status
649
     *
650
     *  @param  int     $status         Id status
651
     *  @param  int     $mode           0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 5=Long label + Picto, 6=Long label + Picto
652
     *  @return string                  Label of status
653
     */
654
    public static function LibStatut($status, $mode = 0)
655
    {
656
		// phpcs:enable
657
        global $langs;
658
659
        $labelStatus = array();
660
        $labelStatusShort = array();
661
        $labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
662
        $labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated') . ' (' . $langs->transnoentitiesnoconv('InventoryStartedShort') . ')';
663
        $labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
664
        $labelStatus[self::STATUS_RECORDED] = $langs->transnoentitiesnoconv('Closed');
665
        $labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
666
        $labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('InventoryStartedShort');
667
        $labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
668
        $labelStatusShort[self::STATUS_RECORDED] = $langs->transnoentitiesnoconv('Closed');
669
670
        $statusType = 'status' . $status;
671
        if ($status == self::STATUS_RECORDED) {
672
            $statusType = 'status6';
673
        }
674
675
        return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', $statusType, $mode);
676
    }
677
678
    /**
679
     *  Return a thumb for kanban views
680
     *
681
     *  @param      string      $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
682
     *  @param      array       $arraydata              Array of data
683
     *  @return     string                              HTML Code for Kanban thumb.
684
     */
685
    public function getKanbanView($option = '', $arraydata = null)
686
    {
687
        global $conf, $langs;
688
689
        $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
690
691
        $return = '<div class="box-flex-item box-flex-grow-zero">';
692
        $return .= '<div class="info-box info-box-sm">';
693
        $return .= '<span class="info-box-icon bg-infobox-action">';
694
        $return .= img_picto('', $this->picto);
695
        $return .= '</span>';
696
        $return .= '<div class="info-box-content">';
697
        $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . (method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref) . '</span>';
698
        if ($selected >= 0) {
699
            $return .= '<input id="cb' . $this->id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
700
        }
701
        if (property_exists($this, 'label')) {
702
            $return .= ' <div class="inline-block opacitymedium valignmiddle tdoverflowmax100">' . $this->label . '</div>';
703
        }
704
        if (property_exists($this, 'amount')) {
705
            $return .= '<br>';
706
            $return .= '<span class="info-box-label amount">' . price($this->amount, 0, $langs, 1, -1, -1, $conf->currency) . '</span>';
0 ignored issues
show
Bug Best Practice introduced by
The property amount does not exist on Dolibarr\Code\Product\Classes\Inventory. Since you implemented __get, consider adding a @property annotation.
Loading history...
707
        }
708
        if (method_exists($this, 'getLibStatut')) {
709
            $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
710
        }
711
        $return .= '</div>';
712
        $return .= '</div>';
713
        $return .= '</div>';
714
715
        return $return;
716
    }
717
718
    /**
719
     *  Charge les information d'ordre info dans l'objet commande
720
     *
721
     *  @param  int     $id       Id of order
722
     *  @return void
723
     */
724
    public function info($id)
725
    {
726
        $sql = "SELECT rowid, date_creation as datec, tms as datem, date_validation as datev,";
727
        $sql .= " fk_user_creat, fk_user_modif, fk_user_valid";
728
        $sql .= " FROM " . $this->db->prefix() . $this->table_element . " as t";
729
        $sql .= " WHERE t.rowid = " . ((int) $id);
730
        $result = $this->db->query($sql);
731
        if ($result) {
732
            if ($this->db->num_rows($result)) {
733
                $obj = $this->db->fetch_object($result);
734
735
                $this->id = $obj->rowid;
736
737
                $this->user_creation_id = $obj->fk_user_creat;
738
                $this->user_modification_id = $obj->fk_user_modif;
739
                $this->user_validation_id = $obj->fk_user_valid;
740
741
                $this->date_creation     = $this->db->jdate($obj->datec);
742
                $this->date_modification = $this->db->jdate($obj->datem);
743
                $this->date_validation   = $this->db->jdate($obj->datev);
744
            }
745
746
            $this->db->free($result);
747
        } else {
748
            dol_print_error($this->db);
749
        }
750
    }
751
752
    /**
753
     * Initialise object with example values
754
     * Id must be 0 if object instance is a specimen
755
     *
756
     * @return int
757
     */
758
    public function initAsSpecimen()
759
    {
760
        $ret = $this->initAsSpecimenCommon();
761
        $this->title = '';
762
763
        return $ret;
764
    }
765
766
    /**
767
     * Return the child warehouse of the current one
768
     *
769
     * @param int   $id                 Id of warehouse
770
     * @param array $TChildWarehouse    Array of child warehouses
771
     * @return int                      Return integer <0 if KO, >0 if OK
772
     */
773
    public function getChildWarehouse($id, &$TChildWarehouse)
774
    {
775
        $sql = 'SELECT rowid FROM ' . MAIN_DB_PREFIX . 'entrepot';
776
        $sql .= ' WHERE fk_parent=' . (int) $id;
777
        $sql .= ' ORDER BY rowid';
778
        $resql = $this->db->query($sql);
779
        if ($resql && $this->db->num_rows($resql) > 0) {
780
            while ($obj = $this->db->fetch_object($resql)) {
781
                $TChildWarehouse[] = $obj->rowid;
782
                $this->getChildWarehouse($obj->rowid, $TChildWarehouse);
783
            }
784
            return 1;
785
        } else {
786
            return -1;
787
        }
788
    }
789
}
790