Completed
Branch develop (b526f7)
by
unknown
29:42
created

BOM::getLibStatut()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) 2019  Laurent Destailleur <[email protected]>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
/**
19
 * \file        bom/class/bom.class.php
20
 * \ingroup     bom
21
 * \brief       This file is a CRUD class file for BOM (Create/Read/Update/Delete)
22
 */
23
24
// Put here all includes required by your class file
25
require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php';
26
//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
27
//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
28
29
/**
30
 * Class for BOM
31
 */
32
class BOM extends CommonObject
33
{
34
	/**
35
	 * @var string ID to identify managed object
36
	 */
37
	public $element = 'bom';
38
39
	/**
40
	 * @var string Name of table without prefix where object is stored
41
	 */
42
	public $table_element = 'bom_bom';
43
44
	/**
45
	 * @var int  Does bom support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
46
	 */
47
	public $ismultientitymanaged = 1;
48
49
	/**
50
	 * @var int  Does bom support extrafields ? 0=No, 1=Yes
51
	 */
52
	public $isextrafieldmanaged = 1;
53
54
	/**
55
	 * @var string String with name of icon for bom. Must be the part after the 'object_' into object_bom.png
56
	 */
57
	public $picto = 'bom';
58
59
60
	public $table_element_line = 'bom_bomline';
61
62
63
	const STATUS_DRAFT = 0;
64
	const STATUS_VALIDATED = 1;
65
	const STATUS_CANCELED = 9;
66
67
68
	/**
69
	 *  'type' if the field format.
70
	 *  'label' the translation key.
71
	 *  'enabled' is a condition when the field must be managed.
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). 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
	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
75
	 *  'default' is a default value for creation (can still be replaced by the global setup of default values)
76
	 *  'index' if we want an index in database.
77
	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
78
	 *  'position' is the sort order of field.
79
	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
80
	 *  '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).
81
	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
82
	 *  'help' is a string visible as a tooltip on field
83
	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
84
	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
85
	 *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
86
	 */
87
88
	// BEGIN MODULEBUILDER PROPERTIES
89
	/**
90
	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
91
	 */
92
	public $fields=array(
93
		'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
94
	    'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'noteditable'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of BOM", 'showoncombobox'=>'1',),
95
		'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>30, 'notnull'=>1, 'searchall'=>1, 'showoncombobox'=>'1',),
96
		'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
97
		'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'help'=>'ProductBOMHelp'),
98
	    'qty' => array('type'=>'real', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>55, 'notnull'=>1, 'isameasure'=>'1', 'css'=>'maxwidth75imp'),
99
		'efficiency' => array('type'=>'real', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>-1, 'default'=>1, 'position'=>100, 'notnull'=>0, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLoss'),
100
		'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>-1, 'position'=>161, 'notnull'=>-1,),
101
		'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>-1, 'position'=>162, 'notnull'=>-1,),
102
		'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>300, 'notnull'=>1,),
103
		'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>1,),
104
		'date_valid' => array('type'=>'datetime', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>502, 'notnull'=>0,),
105
		'fk_user_creat' => array('type'=>'integer', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'llx_user.rowid',),
106
		'fk_user_modif' => array('type'=>'integer', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'position'=>511, 'notnull'=>-1,),
107
		'fk_user_valid' => array('type'=>'integer', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-2, 'position'=>512, 'notnull'=>0,),
108
		'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>900, 'notnull'=>-1,),
109
		'status' => array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>2, 'position'=>1000, 'notnull'=>1, 'default'=>0, 'index'=>1, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Enabled', 9=>'Disabled')),
110
	);
111
	public $rowid;
112
	public $ref;
113
	public $label;
114
	public $description;
115
	public $note_public;
116
	public $note_private;
117
	public $date_creation;
118
	public $tms;
119
	public $fk_user_creat;
120
	public $fk_user_modif;
121
	public $import_key;
122
	public $status;
123
	public $fk_product;
124
	public $qty;
125
	public $efficiency;
126
	// END MODULEBUILDER PROPERTIES
127
128
129
	// If this object has a subtable with lines
130
131
	/**
132
	 * @var int    Name of subtable line
133
	 */
134
	//public $table_element_line = 'bomdet';
135
136
	/**
137
	 * @var int    Field with ID of parent key if this field has a parent
138
	 */
139
	//public $fk_element = 'fk_bom';
140
141
	/**
142
	 * @var int    Name of subtable class that manage subtable lines
143
	 */
144
	//public $class_element_line = 'BillOfMaterialsline';
145
146
	/**
147
	 * @var array  Array of child tables (child tables to delete before deleting a record)
148
	 */
149
	//protected $childtables=array('bomdet');
150
151
	/**
152
	 * @var BillOfMaterialsLine[]     Array of subtable lines
153
	 */
154
	//public $lines = array();
155
156
157
158
	/**
159
	 * Constructor
160
	 *
161
	 * @param DoliDb $db Database handler
162
	 */
163
	public function __construct(DoliDB $db)
164
	{
165
		global $conf, $langs, $user;
166
167
		$this->db = $db;
168
169
		if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) $this->fields['rowid']['visible']=0;
170
		if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) $this->fields['entity']['enabled']=0;
171
172
		// Unset fields that are disabled
173
		foreach($this->fields as $key => $val)
174
		{
175
			if (isset($val['enabled']) && empty($val['enabled']))
176
			{
177
				unset($this->fields[$key]);
178
			}
179
		}
180
181
		// Translate some data of arrayofkeyval
182
		foreach($this->fields as $key => $val)
183
		{
184
			if (is_array($this->fields['status']['arrayofkeyval']))
185
			{
186
				foreach($this->fields['status']['arrayofkeyval'] as $key2 => $val2)
187
				{
188
					$this->fields['status']['arrayofkeyval'][$key2]=$langs->trans($val2);
189
				}
190
			}
191
		}
192
	}
193
194
	/**
195
	 * Create object into database
196
	 *
197
	 * @param  User $user      User that creates
198
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
199
	 * @return int             <0 if KO, Id of created object if OK
200
	 */
201
	public function create(User $user, $notrigger = false)
202
	{
203
		return $this->createCommon($user, $notrigger);
204
	}
205
206
	/**
207
	 * Clone an object into another one
208
	 *
209
	 * @param  	User 	$user      	User that creates
210
	 * @param  	int 	$fromid     Id of object to clone
211
	 * @return 	mixed 				New object created, <0 if KO
212
	 */
213
	public function createFromClone(User $user, $fromid)
214
	{
215
		global $langs, $hookmanager, $extrafields;
216
	    $error = 0;
217
218
	    dol_syslog(__METHOD__, LOG_DEBUG);
219
220
	    $object = new self($this->db);
221
222
	    $this->db->begin();
223
224
	    // Load source object
225
	    $object->fetchCommon($fromid);
226
	    // Reset some properties
227
	    unset($object->id);
228
	    unset($object->fk_user_creat);
229
	    unset($object->import_key);
230
231
	    // Clear fields
232
	    $object->ref = "copy_of_".$object->ref;
233
	    $object->title = $langs->trans("CopyOf")." ".$object->title;
234
	    // ...
235
	    // Clear extrafields that are unique
236
	    if (is_array($object->array_options) && count($object->array_options) > 0)
237
	    {
238
	    	$extrafields->fetch_name_optionals_label($this->element);
239
	    	foreach($object->array_options as $key => $option)
240
	    	{
241
	    		$shortkey = preg_replace('/options_/', '', $key);
242
	    		if (! empty($extrafields->attributes[$this->element]['unique'][$shortkey]))
243
	    		{
244
	    			//var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
245
	    			unset($object->array_options[$key]);
246
	    		}
247
	    	}
248
	    }
249
250
	    // Create clone
251
		$object->context['createfromclone'] = 'createfromclone';
252
	    $result = $object->createCommon($user);
253
	    if ($result < 0) {
254
	        $error++;
255
	        $this->error = $object->error;
256
	        $this->errors = $object->errors;
257
	    }
258
259
	    unset($object->context['createfromclone']);
260
261
	    // End
262
	    if (!$error) {
263
	        $this->db->commit();
264
	        return $object;
265
	    } else {
266
	        $this->db->rollback();
267
	        return -1;
268
	    }
269
	}
270
271
	/**
272
	 * Load object in memory from the database
273
	 *
274
	 * @param int    $id   Id object
275
	 * @param string $ref  Ref
276
	 * @return int         <0 if KO, 0 if not found, >0 if OK
277
	 */
278
	public function fetch($id, $ref = null)
279
	{
280
		$result = $this->fetchCommon($id, $ref);
281
		if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines();
282
		return $result;
283
	}
284
285
	/**
286
	 * Load object lines in memory from the database
287
	 *
288
	 * @return int         <0 if KO, 0 if not found, >0 if OK
289
	 */
290
	public function fetchLines()
291
	{
292
		$this->lines=array();
293
294
		$result = $this->fetchLinesCommon();
295
		return $result;
296
	}
297
298
	/**
299
	 * Load list of objects in memory from the database.
300
	 *
301
	 * @param  string      $sortorder    Sort Order
302
	 * @param  string      $sortfield    Sort field
303
	 * @param  int         $limit        limit
304
	 * @param  int         $offset       Offset
305
	 * @param  array       $filter       Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
306
	 * @param  string      $filtermode   Filter mode (AND or OR)
307
	 * @return array|int                 int <0 if KO, array of pages if OK
308
	 */
309
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
310
	{
311
		global $conf;
312
313
		dol_syslog(__METHOD__, LOG_DEBUG);
314
315
		$records=array();
316
317
		$sql = 'SELECT ';
318
		$sql .= $this->getFieldList();
319
		$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element. ' as t';
320
		if ($this->ismultientitymanaged) $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
321
		else $sql .= ' WHERE 1 = 1';
322
		// Manage filter
323
		$sqlwhere = array();
324
		if (count($filter) > 0) {
325
			foreach ($filter as $key => $value) {
326
				if ($key=='t.rowid') {
327
					$sqlwhere[] = $key . '='. $value;
328
				}
329
				elseif (strpos($key, 'date') !== false) {
330
					$sqlwhere[] = $key.' = \''.$this->db->idate($value).'\'';
331
				}
332
				elseif ($key=='customsql') {
333
					$sqlwhere[] = $value;
334
				}
335
				else {
336
					$sqlwhere[] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\'';
337
				}
338
			}
339
		}
340
		if (count($sqlwhere) > 0) {
341
			$sql .= ' AND (' . implode(' '.$filtermode.' ', $sqlwhere).')';
342
		}
343
344
		if (!empty($sortfield)) {
345
			$sql .= $this->db->order($sortfield, $sortorder);
346
		}
347
		if (!empty($limit)) {
348
			$sql .=  ' ' . $this->db->plimit($limit, $offset);
349
		}
350
351
		$resql = $this->db->query($sql);
352
		if ($resql) {
353
			$num = $this->db->num_rows($resql);
354
355
			while ($obj = $this->db->fetch_object($resql))
356
			{
357
				$record = new self($this->db);
358
				$record->setVarsFromFetchObj($obj);
359
360
				$records[$record->id] = $record;
361
			}
362
			$this->db->free($resql);
363
364
			return $records;
365
		} else {
366
			$this->errors[] = 'Error ' . $this->db->lasterror();
367
			dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
368
369
			return -1;
370
		}
371
	}
372
373
	/**
374
	 * Update object into database
375
	 *
376
	 * @param  User $user      User that modifies
377
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
378
	 * @return int             <0 if KO, >0 if OK
379
	 */
380
	public function update(User $user, $notrigger = false)
381
	{
382
		return $this->updateCommon($user, $notrigger);
383
	}
384
385
	/**
386
	 * Delete object in database
387
	 *
388
	 * @param User $user       User that deletes
389
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
390
	 * @return int             <0 if KO, >0 if OK
391
	 */
392
	public function delete(User $user, $notrigger = false)
393
	{
394
		return $this->deleteCommon($user, $notrigger);
395
		//return $this->deleteCommon($user, $notrigger, 1);
396
	}
397
398
	/**
399
	 *  Delete a line of object in database
400
	 *
401
	 *	@param  User	$user       User that delete
402
	 *  @param	int		$idline		Id of line to delete
403
	 *  @param 	bool 	$notrigger  false=launch triggers after, true=disable triggers
404
	 *  @return int         		>0 if OK, <0 if KO
405
	 */
406
	public function deleteLine(User $user, $idline, $notrigger = false)
407
	{
408
		if ($this->status < 0)
409
		{
410
			$this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
411
			return -2;
412
		}
413
414
		return $this->deleteLineCommon($user, $idline, $notrigger);
415
	}
416
417
	/**
418
	 *  Returns the reference to the following non used BOM depending on the active numbering module
419
	 *  defined into BOM_ADDON
420
	 *
421
	 *  @param	Product		$prod 	Object product
422
	 *  @return string      		BOM free reference
423
	 */
424
	public function getNextNumRef($prod)
425
	{
426
	    global $langs, $conf;
427
	    $langs->load("mrp");
428
429
	    if (! empty($conf->global->BOM_ADDON))
430
	    {
431
	        $mybool=false;
432
433
	        $file = $conf->global->BOM_ADDON.".php";
434
	        $classname = $conf->global->BOM_ADDON;
435
436
	        // Include file with class
437
	        $dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
438
	        foreach ($dirmodels as $reldir)
439
	        {
440
	            $dir = dol_buildpath($reldir."core/modules/bom/");
441
442
	            // Load file with numbering class (if found)
443
	            $mybool|=@include_once $dir.$file;
444
	        }
445
446
	        if ($mybool === false)
447
	        {
448
	            dol_print_error('', "Failed to include file ".$file);
449
	            return '';
450
	        }
451
452
	        $obj = new $classname();
453
	        $numref = $obj->getNextValue($prod, $this);
454
455
	        if ($numref != "")
456
	        {
457
	            return $numref;
458
	        }
459
	        else
460
	        {
461
	            $this->error=$obj->error;
462
	            //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
463
	            return "";
464
	        }
465
	    }
466
	    else
467
	    {
468
	        print $langs->trans("Error")." ".$langs->trans("Error_BOM_ADDON_NotDefined");
469
	        return "";
470
	    }
471
	}
472
473
	/**
474
	 *	Validate bom
475
	 *
476
	 *	@param		User	$user     		User making status change
477
	 *  @param		int		$notrigger		1=Does not execute triggers, 0= execute triggers
478
	 *	@return  	int						<=0 if OK, 0=Nothing done, >0 if KO
479
	 */
480
	public function valid($user, $notrigger = 0)
481
	{
482
	    global $conf, $langs;
483
	    require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
484
485
	    $error=0;
486
487
	    // Protection
488
	    if ($this->statut == self::STATUS_VALIDATED)
489
	    {
490
	        dol_syslog(get_class($this)."::valid action abandonned: already validated", LOG_WARNING);
491
	        return 0;
492
	    }
493
494
	    /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->create))
495
	        || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->bom_advance->validate))))
496
	    {
497
	        $this->error='NotEnoughPermissions';
498
	        dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
499
	        return -1;
500
	    }*/
501
502
	    $now=dol_now();
503
504
	    $this->db->begin();
505
506
	    // Define new ref
507
	    if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
508
	    {
509
	        $this->fetch_product();
510
	        $num = $this->getNextNumRef($this->product);
511
	    }
512
	    else
513
	    {
514
	        $num = $this->ref;
515
	    }
516
	    $this->newref = $num;
517
518
	    // Validate
519
	    $sql = "UPDATE ".MAIN_DB_PREFIX."bom_bom";
520
	    $sql.= " SET ref = '".$this->db->escape($num)."',";
521
	    $sql.= " status = ".self::STATUS_VALIDATED.",";
522
	    $sql.= " date_valid='".$this->db->idate($now)."',";
523
	    $sql.= " fk_user_valid = ".$user->id;
524
	    $sql.= " WHERE rowid = ".$this->id;
525
526
	    dol_syslog(get_class($this)."::valid()", LOG_DEBUG);
527
	    $resql=$this->db->query($sql);
528
	    if (! $resql)
529
	    {
530
	        dol_print_error($this->db);
531
	        $this->error=$this->db->lasterror();
532
	        $error++;
533
	    }
534
535
	    if (! $error && ! $notrigger)
536
	    {
537
	        // Call trigger
538
	        $result=$this->call_trigger('BOM_VALIDATE', $user);
539
	        if ($result < 0) $error++;
540
	        // End call triggers
541
	    }
542
543
	    if (! $error)
544
	    {
545
	        $this->oldref = $this->ref;
546
547
	        // Rename directory if dir was a temporary ref
548
	        if (preg_match('/^[\(]?PROV/i', $this->ref))
549
	        {
550
	            // On renomme repertoire ($this->ref = ancienne ref, $num = nouvelle ref)
551
	            // in order not to lose the attachments
552
	            $oldref = dol_sanitizeFileName($this->ref);
553
	            $newref = dol_sanitizeFileName($num);
554
	            $dirsource = $conf->bom->dir_output.'/'.$oldref;
555
	            $dirdest = $conf->bom->dir_output.'/'.$newref;
556
	            if (file_exists($dirsource))
557
	            {
558
	                dol_syslog(get_class($this)."::valid() rename dir ".$dirsource." into ".$dirdest);
559
560
	                if (@rename($dirsource, $dirdest))
561
	                {
562
	                    dol_syslog("Rename ok");
563
	                    // Rename docs starting with $oldref with $newref
564
	                    $listoffiles=dol_dir_list($conf->bom->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
565
	                    foreach($listoffiles as $fileentry)
566
	                    {
567
	                        $dirsource=$fileentry['name'];
568
	                        $dirdest=preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
569
	                        $dirsource=$fileentry['path'].'/'.$dirsource;
570
	                        $dirdest=$fileentry['path'].'/'.$dirdest;
571
	                        @rename($dirsource, $dirdest);
572
	                    }
573
	                }
574
	            }
575
	        }
576
	    }
577
578
	    // Set new ref and current status
579
	    if (! $error)
580
	    {
581
	        $this->ref = $num;
582
	        $this->status = self::STATUS_VALIDATED;
583
	    }
584
585
	    if (! $error)
586
	    {
587
	        $this->db->commit();
588
	        return 1;
589
	    }
590
	    else
591
	    {
592
	        $this->db->rollback();
593
	        return -1;
594
	    }
595
	}
596
597
	/**
598
	 *	Set draft status
599
	 *
600
	 *	@param	User	$user			Object user that modify
601
	 *	@return	int						<0 if KO, >0 if OK
602
	 */
603
	public function setDraft($user)
604
	{
605
	    global $conf, $langs;
606
607
	    $error=0;
608
609
	    // Protection
610
	    if ($this->status <= self::STATUS_DRAFT)
611
	    {
612
	        return 0;
613
	    }
614
615
	    /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->write))
616
	        || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->bom->bom_advance->validate))))
617
	    {
618
	        $this->error='Permission denied';
619
	        return -1;
620
	    }*/
621
622
	    $this->db->begin();
623
624
	    $sql = "UPDATE ".MAIN_DB_PREFIX."bom";
625
	    $sql.= " SET status = ".self::STATUS_DRAFT;
626
	    $sql.= " WHERE rowid = ".$this->id;
627
628
	    dol_syslog(get_class($this)."::setDraft", LOG_DEBUG);
629
	    if ($this->db->query($sql))
630
	    {
631
	        if (! $error)
632
	        {
633
	            $this->oldcopy= clone $this;
634
	        }
635
636
	        if (!$error) {
637
	            // Call trigger
638
	            $result=$this->call_trigger('BOM_UNVALIDATE', $user);
639
	            if ($result < 0) $error++;
640
	        }
641
642
	        if (!$error) {
643
	            $this->status=self::STATUS_DRAFT;
644
	            $this->db->commit();
645
	            return 1;
646
	        } else {
647
	            $this->db->rollback();
648
	            return -1;
649
	        }
650
	    }
651
	    else
652
	    {
653
	        $this->error=$this->db->error();
654
	        $this->db->rollback();
655
	        return -1;
656
	    }
657
	}
658
659
	/**
660
	 *  Return a link to the object card (with optionaly the picto)
661
	 *
662
	 *	@param	int		$withpicto					Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
663
	 *	@param	string	$option						On what the link point to ('nolink', ...)
664
     *  @param	int  	$notooltip					1=Disable tooltip
665
     *  @param  string  $morecss            		Add more css on link
666
     *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
667
	 *	@return	string								String with URL
668
	 */
669
	public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
670
	{
671
		global $db, $conf, $langs, $hookmanager;
672
        global $dolibarr_main_authentication, $dolibarr_main_demo;
673
        global $menumanager;
674
675
        if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
676
677
        $result = '';
678
679
        $label = '<u>' . $langs->trans("BillOfMaterials") . '</u>';
680
        $label.= '<br>';
681
        $label.= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
682
683
        $url = dol_buildpath('/bom/bom_card.php', 1).'?id='.$this->id;
684
685
        if ($option != 'nolink')
686
        {
687
	        // Add param to save lastsearch_values or not
688
	        $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
689
	        if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
690
	        if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
691
        }
692
693
        $linkclose='';
694
        if (empty($notooltip))
695
        {
696
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
697
            {
698
                $label=$langs->trans("ShowBillOfMaterials");
699
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
700
            }
701
            $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"';
702
            $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"';
703
704
            /*
705
             $hookmanager->initHooks(array('bomdao'));
706
             $parameters=array('id'=>$this->id);
707
             $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
708
             if ($reshook > 0) $linkclose = $hookmanager->resPrint;
709
             */
710
        }
711
        else $linkclose = ($morecss?' class="'.$morecss.'"':'');
712
713
		$linkstart = '<a href="'.$url.'"';
714
		$linkstart.=$linkclose.'>';
715
		$linkend='</a>';
716
717
		$result .= $linkstart;
718
		if ($withpicto) $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);
719
		if ($withpicto != 2) $result.= $this->ref;
720
		$result .= $linkend;
721
		//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
722
723
		global $action,$hookmanager;
724
		$hookmanager->initHooks(array('bomdao'));
725
		$parameters=array('id'=>$this->id, 'getnomurl'=>$result);
726
		$reshook=$hookmanager->executeHooks('getNomUrl', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
727
		if ($reshook > 0) $result = $hookmanager->resPrint;
728
		else $result .= $hookmanager->resPrint;
729
730
		return $result;
731
	}
732
733
	/**
734
	 *  Return label of the status
735
	 *
736
	 *  @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
737
	 *  @return	string 			       Label of status
738
	 */
739
	public function getLibStatut($mode = 0)
740
	{
741
		return $this->LibStatut($this->status, $mode);
742
	}
743
744
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
745
	/**
746
	 *  Return the status
747
	 *
748
	 *  @param	int		$status        Id status
749
	 *  @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
750
	 *  @return string 			       Label of status
751
	 */
752
	public function LibStatut($status, $mode = 0)
753
	{
754
		// phpcs:enable
755
		if (empty($this->labelstatus))
756
		{
757
			global $langs;
758
			//$langs->load("mrp");
759
			$this->labelstatus[self::STATUS_DRAFT] = $langs->trans('Draft');
760
			$this->labelstatus[self::STATUS_VALIDATED] = $langs->trans('Enabled');
761
			$this->labelstatus[self::STATUS_CANCELED] = $langs->trans('Disabled');
762
		}
763
764
		if ($mode == 0)
765
		{
766
			return $this->labelstatus[$status];
767
		}
768
		elseif ($mode == 1)
769
		{
770
			return $this->labelstatus[$status];
771
		}
772
		elseif ($mode == 2)
773
		{
774
			return img_picto($this->labelstatus[$status], 'statut'.($status == self::STATUS_VALIDATED ? 4 : $status), '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
775
		}
776
		elseif ($mode == 3)
777
		{
778
			return img_picto($this->labelstatus[$status], 'statut'.($status == self::STATUS_VALIDATED ? 4 : $status), '', false, 0, 0, '', 'valignmiddle');
779
		}
780
		elseif ($mode == 4)
781
		{
782
			return img_picto($this->labelstatus[$status], 'statut'.($status == self::STATUS_VALIDATED ? 4 : $status), '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
783
		}
784
		elseif ($mode == 5)
785
		{
786
			return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut'.($status == self::STATUS_VALIDATED ? 4 : $status), '', false, 0, 0, '', 'valignmiddle');
787
		}
788
		elseif ($mode == 6)
789
		{
790
			return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut'.($status == self::STATUS_VALIDATED ? 4 : $status), '', false, 0, 0, '', 'valignmiddle');
791
		}
792
	}
793
794
	/**
795
	 *	Load the info information in the object
796
	 *
797
	 *	@param  int		$id       Id of object
798
	 *	@return	void
799
	 */
800
	public function info($id)
801
	{
802
		$sql = 'SELECT rowid, date_creation as datec, tms as datem,';
803
		$sql.= ' fk_user_creat, fk_user_modif';
804
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
805
		$sql.= ' WHERE t.rowid = '.$id;
806
		$result=$this->db->query($sql);
807
		if ($result)
808
		{
809
			if ($this->db->num_rows($result))
810
			{
811
				$obj = $this->db->fetch_object($result);
812
				$this->id = $obj->rowid;
813
				if ($obj->fk_user_author)
814
				{
815
					$cuser = new User($this->db);
816
					$cuser->fetch($obj->fk_user_author);
817
					$this->user_creation   = $cuser;
818
				}
819
820
				if ($obj->fk_user_valid)
821
				{
822
					$vuser = new User($this->db);
823
					$vuser->fetch($obj->fk_user_valid);
824
					$this->user_validation = $vuser;
825
				}
826
827
				if ($obj->fk_user_cloture)
828
				{
829
					$cluser = new User($this->db);
830
					$cluser->fetch($obj->fk_user_cloture);
831
					$this->user_cloture   = $cluser;
832
				}
833
834
				$this->date_creation     = $this->db->jdate($obj->datec);
835
				$this->date_modification = $this->db->jdate($obj->datem);
836
				$this->date_validation   = $this->db->jdate($obj->datev);
837
			}
838
839
			$this->db->free($result);
840
		}
841
		else
842
		{
843
			dol_print_error($this->db);
844
		}
845
	}
846
847
	/**
848
	 * 	Create an array of lines
849
	 *
850
	 * 	@return array|int		array of lines if OK, <0 if KO
851
	 */
852
	public function getLinesArray()
853
	{
854
	    $this->lines=array();
855
856
	    $objectline = new BOMLine($this->db);
857
	    $result = $objectline->fetchAll('', '', 0, 0, array('customsql'=>'fk_bom = '.$this->id));
858
859
	    if (is_numeric($result))
860
	    {
861
	        $this->error = $this->error;
862
	        $this->errors = $this->errors;
863
	        return $result;
864
	    }
865
	    else
866
	    {
867
	        $this->lines = $result;
868
	        return $this->lines;
869
	    }
870
	}
871
872
	/**
873
	 *  Create a document onto disk according to template module.
874
	 *
875
	 *  @param	    string		$modele			Force template to use ('' to not force)
876
	 *  @param		Translate	$outputlangs	objet lang a utiliser pour traduction
877
	 *  @param      int			$hidedetails    Hide details of lines
878
	 *  @param      int			$hidedesc       Hide description
879
	 *  @param      int			$hideref        Hide ref
880
	 *  @param      null|array  $moreparams     Array to provide more information
881
	 *  @return     int         				0 if KO, 1 if OK
882
	 */
883
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
884
	{
885
		global $conf,$langs;
886
887
		$langs->load("mrp");
888
889
		if (! dol_strlen($modele)) {
890
891
			$modele = 'standard';
892
893
			if ($this->modelpdf) {
894
				$modele = $this->modelpdf;
895
			} elseif (! empty($conf->global->BOM_ADDON_PDF)) {
896
				$modele = $conf->global->BOM_ADDON_PDF;
897
			}
898
		}
899
900
		$modelpath = "core/modules/bom/doc/";
901
902
		//return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
903
		return 1;
904
	}
905
906
	/**
907
	 * Initialise object with example values
908
	 * Id must be 0 if object instance is a specimen
909
	 *
910
	 * @return void
911
	 */
912
	public function initAsSpecimen()
913
	{
914
	    $this->initAsSpecimenCommon();
915
	    $this->date = $this->date_creation;
916
	}
917
918
919
	/**
920
	 * Action executed by scheduler
921
	 * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters'
922
	 *
923
	 * @return	int			0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
924
	 */
925
	//public function doScheduledJob($param1, $param2, ...)
926
	public function doScheduledJob()
927
	{
928
		global $conf, $langs;
929
930
		//$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
931
932
		$error = 0;
933
		$this->output = '';
934
		$this->error='';
935
936
		dol_syslog(__METHOD__, LOG_DEBUG);
937
938
		$now = dol_now();
939
940
		$this->db->begin();
941
942
		// ...
943
944
		$this->db->commit();
945
946
		return $error;
947
	}
948
}
949
950
951
/**
952
 * Class for BOMLine
953
 */
954
class BOMLine extends CommonObject
955
{
956
	/**
957
	 * @var string ID to identify managed object
958
	 */
959
	public $element = 'bomline';
960
961
	/**
962
	 * @var string Name of table without prefix where object is stored
963
	 */
964
	public $table_element = 'bom_bomline';
965
966
	/**
967
	 * @var int  Does bomline support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
968
	 */
969
	public $ismultientitymanaged = 0;
970
971
	/**
972
	 * @var int  Does bomline support extrafields ? 0=No, 1=Yes
973
	 */
974
	public $isextrafieldmanaged = 1;
975
976
	/**
977
	 * @var string String with name of icon for bomline. Must be the part after the 'object_' into object_bomline.png
978
	 */
979
	public $picto = 'bomline';
980
981
982
	/**
983
	 *  'type' if the field format.
984
	 *  'label' the translation key.
985
	 *  'enabled' is a condition when the field must be managed.
986
	 *  '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. Using a negative value means field is not shown by default on list but can be selected for viewing)
987
	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
988
	 *  'default' is a default value for creation (can still be replaced by the global setup of default values)
989
	 *  'index' if we want an index in database.
990
	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
991
	 *  'position' is the sort order of field.
992
	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
993
	 *  '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).
994
	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
995
	 *  'help' is a string visible as a tooltip on field
996
	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
997
	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
998
	 *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
999
	 */
1000
1001
	// BEGIN MODULEBUILDER PROPERTIES
1002
	/**
1003
	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
1004
	 */
1005
	public $fields=array(
1006
		'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
1007
		'fk_bom' => array('type'=>'integer:BillOfMaterials:societe/class/bom.class.php', 'label'=>'BillOfMaterials', 'enabled'=>1, 'visible'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1,),
1008
		'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
1009
		'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,),
1010
		'qty' => array('type'=>'double(24,8)', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'position'=>100, 'notnull'=>1, 'isameasure'=>'1',),
1011
		'efficiency' => array('type'=>'double(8,4)', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>110, 'notnull'=>1, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLoss'),
1012
		'rank' => array('type'=>'integer', 'label'=>'Rank', 'enabled'=>1, 'visible'=>0, 'position'=>200, 'notnull'=>1,),
1013
		'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
1014
	);
1015
	public $rowid;
1016
	public $fk_bom;
1017
	public $fk_product;
1018
	public $description;
1019
	public $qty;
1020
	public $efficiency;
1021
	public $rank;
1022
	public $import_key;
1023
	// END MODULEBUILDER PROPERTIES
1024
1025
1026
	/**
1027
	 * Constructor
1028
	 *
1029
	 * @param DoliDb $db Database handler
1030
	 */
1031
	public function __construct(DoliDB $db)
1032
	{
1033
		global $conf, $langs, $user;
1034
1035
		$this->db = $db;
1036
1037
		if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) $this->fields['rowid']['visible']=0;
1038
		if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) $this->fields['entity']['enabled']=0;
1039
1040
		// Unset fields that are disabled
1041
		foreach($this->fields as $key => $val)
1042
		{
1043
			if (isset($val['enabled']) && empty($val['enabled']))
1044
			{
1045
				unset($this->fields[$key]);
1046
			}
1047
		}
1048
1049
		// Translate some data of arrayofkeyval
1050
		foreach($this->fields as $key => $val)
1051
		{
1052
			if (is_array($this->fields['status']['arrayofkeyval']))
1053
			{
1054
				foreach($this->fields['status']['arrayofkeyval'] as $key2 => $val2)
1055
				{
1056
					$this->fields['status']['arrayofkeyval'][$key2]=$langs->trans($val2);
1057
				}
1058
			}
1059
		}
1060
	}
1061
1062
	/**
1063
	 * Create object into database
1064
	 *
1065
	 * @param  User $user      User that creates
1066
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
1067
	 * @return int             <0 if KO, Id of created object if OK
1068
	 */
1069
	public function create(User $user, $notrigger = false)
1070
	{
1071
		return $this->createCommon($user, $notrigger);
1072
	}
1073
1074
	/**
1075
	 * Clone an object into another one
1076
	 *
1077
	 * @param  	User 	$user      	User that creates
1078
	 * @param  	int 	$fromid     Id of object to clone
1079
	 * @return 	mixed 				New object created, <0 if KO
1080
	 */
1081
	public function createFromClone(User $user, $fromid)
1082
	{
1083
		global $langs, $hookmanager, $extrafields;
1084
	    $error = 0;
1085
1086
	    dol_syslog(__METHOD__, LOG_DEBUG);
1087
1088
	    $object = new self($this->db);
1089
1090
	    $this->db->begin();
1091
1092
	    // Load source object
1093
	    $object->fetchCommon($fromid);
1094
	    // Reset some properties
1095
	    unset($object->id);
1096
	    unset($object->fk_user_creat);
1097
	    unset($object->import_key);
1098
1099
	    // Clear fields
1100
	    $object->ref = "copy_of_".$object->ref;
1101
	    $object->title = $langs->trans("CopyOf")." ".$object->title;
1102
	    // ...
1103
	    // Clear extrafields that are unique
1104
	    if (is_array($object->array_options) && count($object->array_options) > 0)
1105
	    {
1106
	    	$extrafields->fetch_name_optionals_label($this->element);
1107
	    	foreach($object->array_options as $key => $option)
1108
	    	{
1109
	    		$shortkey = preg_replace('/options_/', '', $key);
1110
	    		if (! empty($extrafields->attributes[$this->element]['unique'][$shortkey]))
1111
	    		{
1112
	    			//var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
1113
	    			unset($object->array_options[$key]);
1114
	    		}
1115
	    	}
1116
	    }
1117
1118
	    // Create clone
1119
		$object->context['createfromclone'] = 'createfromclone';
1120
	    $result = $object->createCommon($user);
1121
	    if ($result < 0) {
1122
	        $error++;
1123
	        $this->error = $object->error;
1124
	        $this->errors = $object->errors;
1125
	    }
1126
1127
	    unset($object->context['createfromclone']);
1128
1129
	    // End
1130
	    if (!$error) {
1131
	        $this->db->commit();
1132
	        return $object;
1133
	    } else {
1134
	        $this->db->rollback();
1135
	        return -1;
1136
	    }
1137
	}
1138
1139
	/**
1140
	 * Load object in memory from the database
1141
	 *
1142
	 * @param int    $id   Id object
1143
	 * @param string $ref  Ref
1144
	 * @return int         <0 if KO, 0 if not found, >0 if OK
1145
	 */
1146
	public function fetch($id, $ref = null)
1147
	{
1148
		$result = $this->fetchCommon($id, $ref);
1149
		//if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines();
1150
		return $result;
1151
	}
1152
1153
	/**
1154
	 * Load list of objects in memory from the database.
1155
	 *
1156
	 * @param  string      $sortorder    Sort Order
1157
	 * @param  string      $sortfield    Sort field
1158
	 * @param  int         $limit        limit
1159
	 * @param  int         $offset       Offset
1160
	 * @param  array       $filter       Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
1161
	 * @param  string      $filtermode   Filter mode (AND or OR)
1162
	 * @return array|int                 int <0 if KO, array of pages if OK
1163
	 */
1164
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
1165
	{
1166
		global $conf;
1167
1168
		dol_syslog(__METHOD__, LOG_DEBUG);
1169
1170
		$records=array();
1171
1172
		$sql = 'SELECT ';
1173
		$sql .= $this->getFieldList();
1174
		$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element. ' as t';
1175
		if ($this->ismultientitymanaged) $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
1176
		else $sql .= ' WHERE 1 = 1';
1177
		// Manage filter
1178
		$sqlwhere = array();
1179
		if (count($filter) > 0) {
1180
			foreach ($filter as $key => $value) {
1181
				if ($key=='t.rowid') {
1182
					$sqlwhere[] = $key . '='. $value;
1183
				}
1184
				elseif (strpos($key, 'date') !== false) {
1185
					$sqlwhere[] = $key.' = \''.$this->db->idate($value).'\'';
1186
				}
1187
				elseif ($key=='customsql') {
1188
					$sqlwhere[] = $value;
1189
				}
1190
				else {
1191
					$sqlwhere[] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\'';
1192
				}
1193
			}
1194
		}
1195
		if (count($sqlwhere) > 0) {
1196
			$sql .= ' AND (' . implode(' '.$filtermode.' ', $sqlwhere).')';
1197
		}
1198
1199
		if (!empty($sortfield)) {
1200
			$sql .= $this->db->order($sortfield, $sortorder);
1201
		}
1202
		if (!empty($limit)) {
1203
			$sql .=  ' ' . $this->db->plimit($limit, $offset);
1204
		}
1205
1206
		$resql = $this->db->query($sql);
1207
		if ($resql) {
1208
			$num = $this->db->num_rows($resql);
1209
1210
			while ($obj = $this->db->fetch_object($resql))
1211
			{
1212
				$record = new self($this->db);
1213
				$record->setVarsFromFetchObj($obj);
1214
1215
				$records[$record->id] = $record;
1216
			}
1217
			$this->db->free($resql);
1218
1219
			return $records;
1220
		} else {
1221
			$this->errors[] = 'Error ' . $this->db->lasterror();
1222
			dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
1223
1224
			return -1;
1225
		}
1226
	}
1227
1228
	/**
1229
	 * Update object into database
1230
	 *
1231
	 * @param  User $user      User that modifies
1232
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
1233
	 * @return int             <0 if KO, >0 if OK
1234
	 */
1235
	public function update(User $user, $notrigger = false)
1236
	{
1237
		return $this->updateCommon($user, $notrigger);
1238
	}
1239
1240
	/**
1241
	 * Delete object in database
1242
	 *
1243
	 * @param User $user       User that deletes
1244
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
1245
	 * @return int             <0 if KO, >0 if OK
1246
	 */
1247
	public function delete(User $user, $notrigger = false)
1248
	{
1249
		return $this->deleteCommon($user, $notrigger);
1250
		//return $this->deleteCommon($user, $notrigger, 1);
1251
	}
1252
1253
	/**
1254
	 *  Return a link to the object card (with optionaly the picto)
1255
	 *
1256
	 *	@param	int		$withpicto					Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
1257
	 *	@param	string	$option						On what the link point to ('nolink', ...)
1258
     *  @param	int  	$notooltip					1=Disable tooltip
1259
     *  @param  string  $morecss            		Add more css on link
1260
     *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
1261
     *  @return	string								String with URL
1262
     */
1263
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
1264
    {
1265
        global $db, $conf, $langs, $hookmanager;
1266
        global $dolibarr_main_authentication, $dolibarr_main_demo;
1267
        global $menumanager;
1268
1269
        if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
1270
1271
        $result = '';
1272
1273
        $label = '<u>' . $langs->trans("BillOfMaterialsLine") . '</u>';
1274
        $label.= '<br>';
1275
        $label.= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
1276
1277
        $url = dol_buildpath('/bom/bomline_card.php', 1).'?id='.$this->id;
1278
1279
        if ($option != 'nolink')
1280
        {
1281
	        // Add param to save lastsearch_values or not
1282
	        $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
1283
	        if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
1284
	        if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
1285
        }
1286
1287
        $linkclose='';
1288
        if (empty($notooltip))
1289
        {
1290
            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1291
            {
1292
                $label=$langs->trans("ShowBillOfMaterialsLine");
1293
                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
1294
            }
1295
            $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"';
1296
            $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"';
1297
1298
            /*
1299
             $hookmanager->initHooks(array('bomlinedao'));
1300
             $parameters=array('id'=>$this->id);
1301
             $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
1302
             if ($reshook > 0) $linkclose = $hookmanager->resPrint;
1303
             */
1304
        }
1305
        else $linkclose = ($morecss?' class="'.$morecss.'"':'');
1306
1307
		$linkstart = '<a href="'.$url.'"';
1308
		$linkstart.=$linkclose.'>';
1309
		$linkend='</a>';
1310
1311
		$result .= $linkstart;
1312
		if ($withpicto) $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);
1313
		if ($withpicto != 2) $result.= $this->ref;
1314
		$result .= $linkend;
1315
		//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
1316
1317
		global $action,$hookmanager;
1318
		$hookmanager->initHooks(array('bomlinedao'));
1319
		$parameters=array('id'=>$this->id, 'getnomurl'=>$result);
1320
		$reshook=$hookmanager->executeHooks('getNomUrl', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
1321
		if ($reshook > 0) $result = $hookmanager->resPrint;
1322
		else $result .= $hookmanager->resPrint;
1323
1324
		return $result;
1325
    }
1326
1327
	/**
1328
	 *  Return label of the status
1329
	 *
1330
	 *  @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
1331
	 *  @return	string 			       Label of status
1332
	 */
1333
	public function getLibStatut($mode = 0)
1334
	{
1335
		return $this->LibStatut($this->status, $mode);
1336
	}
1337
1338
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1339
	/**
1340
	 *  Return the status
1341
	 *
1342
	 *  @param	int		$status        Id status
1343
	 *  @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
1344
	 *  @return string 			       Label of status
1345
	 */
1346
	public function LibStatut($status, $mode = 0)
1347
	{
1348
		// phpcs:enable
1349
		if (empty($this->labelstatus))
1350
		{
1351
			global $langs;
1352
			//$langs->load("mrp");
1353
			$this->labelstatus[1] = $langs->trans('Enabled');
1354
			$this->labelstatus[0] = $langs->trans('Disabled');
1355
		}
1356
1357
		if ($mode == 0)
1358
		{
1359
			return $this->labelstatus[$status];
1360
		}
1361
		elseif ($mode == 1)
1362
		{
1363
			return $this->labelstatus[$status];
1364
		}
1365
		elseif ($mode == 2)
1366
		{
1367
			if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
1368
			elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
1369
		}
1370
		elseif ($mode == 3)
1371
		{
1372
			if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle');
1373
			elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle');
1374
		}
1375
		elseif ($mode == 4)
1376
		{
1377
			if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
1378
			elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status];
1379
		}
1380
		elseif ($mode == 5)
1381
		{
1382
			if ($status == 1) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle');
1383
			elseif ($status == 0) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle');
1384
		}
1385
		elseif ($mode == 6)
1386
		{
1387
			if ($status == 1) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle');
1388
			elseif ($status == 0) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle');
1389
		}
1390
	}
1391
1392
	/**
1393
	 *	Load the info information in the object
1394
	 *
1395
	 *	@param  int		$id       Id of object
1396
	 *	@return	void
1397
	 */
1398
	public function info($id)
1399
	{
1400
		$sql = 'SELECT rowid, date_creation as datec, tms as datem,';
1401
		$sql.= ' fk_user_creat, fk_user_modif';
1402
		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1403
		$sql.= ' WHERE t.rowid = '.$id;
1404
		$result=$this->db->query($sql);
1405
		if ($result)
1406
		{
1407
			if ($this->db->num_rows($result))
1408
			{
1409
				$obj = $this->db->fetch_object($result);
1410
				$this->id = $obj->rowid;
1411
				if ($obj->fk_user_author)
1412
				{
1413
					$cuser = new User($this->db);
1414
					$cuser->fetch($obj->fk_user_author);
1415
					$this->user_creation   = $cuser;
1416
				}
1417
1418
				if ($obj->fk_user_valid)
1419
				{
1420
					$vuser = new User($this->db);
1421
					$vuser->fetch($obj->fk_user_valid);
1422
					$this->user_validation = $vuser;
1423
				}
1424
1425
				if ($obj->fk_user_cloture)
1426
				{
1427
					$cluser = new User($this->db);
1428
					$cluser->fetch($obj->fk_user_cloture);
1429
					$this->user_cloture   = $cluser;
1430
				}
1431
1432
				$this->date_creation     = $this->db->jdate($obj->datec);
1433
				$this->date_modification = $this->db->jdate($obj->datem);
1434
				$this->date_validation   = $this->db->jdate($obj->datev);
1435
			}
1436
1437
			$this->db->free($result);
1438
		}
1439
		else
1440
		{
1441
			dol_print_error($this->db);
1442
		}
1443
	}
1444
1445
	/**
1446
	 * Initialise object with example values
1447
	 * Id must be 0 if object instance is a specimen
1448
	 *
1449
	 * @return void
1450
	 */
1451
	public function initAsSpecimen()
1452
	{
1453
		$this->initAsSpecimenCommon();
1454
	}
1455
}
1456