Passed
Branch develop (8190a6)
by
unknown
25:05
created

Mo::printOriginLine()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
c 0
b 0
f 0
nc 2
nop 5
dl 0
loc 27
rs 9.8333
1
<?php
2
/* Copyright (C) 2017  Laurent Destailleur <[email protected]>
3
 * Copyright (C) ---Put here your own copyright and developer email---
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
/**
20
 * \file        class/mo.class.php
21
 * \ingroup     mrp
22
 * \brief       This file is a CRUD class file for Mo (Create/Read/Update/Delete)
23
 */
24
25
// Put here all includes required by your class file
26
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27
//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
28
//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
29
30
/**
31
 * Class for Mo
32
 */
33
class Mo extends CommonObject
34
{
35
	/**
36
	 * @var string ID to identify managed object
37
	 */
38
	public $element = 'mo';
39
40
	/**
41
	 * @var string Name of table without prefix where object is stored
42
	 */
43
	public $table_element = 'mrp_mo';
44
45
	/**
46
	 * @var int  Does mo support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
47
	 */
48
	public $ismultientitymanaged = 0;
49
50
	/**
51
	 * @var int  Does mo support extrafields ? 0=No, 1=Yes
52
	 */
53
	public $isextrafieldmanaged = 1;
54
55
	/**
56
	 * @var string String with name of icon for mo. Must be the part after the 'object_' into object_mo.png
57
	 */
58
	public $picto = 'mrp';
59
60
61
	const STATUS_DRAFT = 0;
62
	const STATUS_VALIDATED = 1; // To produce
63
	const STATUS_INPROGRESS = 2;
64
	const STATUS_PRODUCED = 3;
65
	const STATUS_CANCELED = -1;
66
67
68
69
	/**
70
	 *  'type' if the field format ('integer', 'integer:Class:pathtoclass', 'varchar(x)', 'double(24,8)', 'text', 'html', 'datetime', 'timestamp', 'float')
71
	 *  'label' the translation key.
72
	 *  'enabled' is a condition when the field must be managed.
73
	 *  '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)
74
	 *  'noteditable' says if field is not editable (1 or 0)
75
	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
76
	 *  'default' is a default value for creation (can still be replaced by the global setup of default values)
77
	 *  'index' if we want an index in database.
78
	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
79
	 *  'position' is the sort order of field.
80
	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
81
	 *  '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).
82
	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
83
	 *  'help' is a string visible as a tooltip on field
84
	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
85
	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
86
	 *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
87
	 */
88
89
	// BEGIN MODULEBUILDER PROPERTIES
90
	/**
91
	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
92
	 */
93
	public $fields = array(
94
		'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>"Id",),
95
		'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'position'=>5, 'notnull'=>1, 'default'=>'1', 'index'=>1,),
96
		'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of object", 'showoncombobox'=>'1',),
97
		'fk_bom' => array('type'=>'integer:Bom:bom/class/bom.class.php:0:t.status=1', 'filter'=>'active=1', 'label'=>'BOM', 'enabled'=>1, 'visible'=>1, 'position'=>33, 'notnull'=>-1, 'index'=>1, 'comment'=>"Original BOM",),
98
		'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:0', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'comment'=>"Product to produce",),
99
		'qty' => array('type'=>'real', 'label'=>'QtyToProduce', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'notnull'=>1, 'comment'=>"Qty to produce",),
100
		'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>42, 'notnull'=>-1, 'searchall'=>1, 'showoncombobox'=>'1',),
101
		'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php:1', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'position'=>50, 'notnull'=>-1, 'index'=>1),
102
	    'fk_warehouse' => array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php:0', 'label'=>'WarehouseForProduction', 'enabled'=>1, 'visible'=>-1, 'position'=>52),
103
	    'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>61, 'notnull'=>-1,),
104
		'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>62, 'notnull'=>-1,),
105
		'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>500, 'notnull'=>1,),
106
		'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'position'=>501, 'notnull'=>-1,),
107
		'fk_user_creat' => array('type'=>'integer', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'position'=>510, 'notnull'=>1, 'foreignkey'=>'user.rowid',),
108
		'fk_user_modif' => array('type'=>'integer', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'position'=>511, 'notnull'=>-1,),
109
		'date_start_planned' => array('type'=>'datetime', 'label'=>'DateStartPlannedMo', 'enabled'=>1, 'visible'=>1, 'position'=>55, 'notnull'=>-1, 'index'=>1, 'help'=>'KeepEmptyForAsap'),
110
		'date_end_planned' => array('type'=>'datetime', 'label'=>'DateEndPlannedMo', 'enabled'=>1, 'visible'=>1, 'position'=>56, 'notnull'=>-1, 'index'=>1,),
111
		'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>1, 'visible'=>-1, 'position'=>52, 'notnull'=>-1, 'index'=>1,),
112
		'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000, 'notnull'=>-1,),
113
		'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>1010),
114
		'status' => array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>2, 'position'=>1000, 'default'=>0, 'notnull'=>1, 'index'=>1, 'arrayofkeyval'=>array('0'=>'Brouillon', '1'=>'Validated', '2'=>'InProgress', '3'=>'StatusMOProduced', '-1'=>'Canceled')),
115
	);
116
	public $rowid;
117
	public $ref;
118
	public $entity;
119
	public $label;
120
	public $qty;
121
	public $fk_warehouse;
122
	public $fk_soc;
123
124
	/**
125
	 * @var string public note
126
	 */
127
	public $note_public;
128
129
	/**
130
	 * @var string private note
131
	 */
132
	public $note_private;
133
134
	/**
135
	 * @var integer|string date_creation
136
	 */
137
	public $date_creation;
138
139
140
	public $tms;
141
	public $fk_user_creat;
142
	public $fk_user_modif;
143
	public $import_key;
144
	public $status;
145
	public $fk_product;
146
147
	/**
148
	 * @var integer|string date_start_planned
149
	 */
150
	public $date_start_planned;
151
152
	/**
153
	 * @var integer|string date_end_planned
154
	 */
155
	public $date_end_planned;
156
157
158
	public $fk_bom;
159
	public $fk_project;
160
	// END MODULEBUILDER PROPERTIES
161
162
163
	// If this object has a subtable with lines
164
165
	/**
166
	 * @var int    Name of subtable line
167
	 */
168
	public $table_element_line = 'mo_production';
169
170
	/**
171
	 * @var int    Field with ID of parent key if this field has a parent
172
	 */
173
	public $fk_element = 'fk_mo';
174
175
	/**
176
	 * @var int    Name of subtable class that manage subtable lines
177
	 */
178
	public $class_element_line = 'MoLine';
179
180
	/**
181
	 * @var array	List of child tables. To test if we can delete object.
182
	 */
183
	protected $childtables=array();
184
185
	/**
186
	 * @var array	List of child tables. To know object to delete on cascade.
187
	 */
188
	protected $childtablesoncascade=array('mrp_production');
189
190
	/**
191
	 * @var MoLine[]     Array of subtable lines
192
	 */
193
	public $lines = array();
194
195
196
197
	/**
198
	 * Constructor
199
	 *
200
	 * @param DoliDb $db Database handler
201
	 */
202
	public function __construct(DoliDB $db)
203
	{
204
		global $conf, $langs;
205
206
		$this->db = $db;
207
208
		if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) $this->fields['rowid']['visible'] = 0;
209
		if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) $this->fields['entity']['enabled'] = 0;
210
211
		// Unset fields that are disabled
212
		foreach ($this->fields as $key => $val)
213
		{
214
			if (isset($val['enabled']) && empty($val['enabled']))
215
			{
216
				unset($this->fields[$key]);
217
			}
218
		}
219
220
		// Translate some data of arrayofkeyval
221
		foreach ($this->fields as $key => $val)
222
		{
223
			if (is_array($val['arrayofkeyval']))
224
			{
225
				foreach ($val['arrayofkeyval'] as $key2 => $val2)
226
				{
227
					$this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
228
				}
229
			}
230
		}
231
	}
232
233
	/**
234
	 * Create object into database
235
	 *
236
	 * @param  User $user      User that creates
237
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
238
	 * @return int             <0 if KO, Id of created object if OK
239
	 */
240
	public function create(User $user, $notrigger = false)
241
	{
242
		global $conf;
243
244
		$error = 0;
245
246
		$this->db->begin();
247
248
		$result = $this->createCommon($user, $notrigger);
249
		if ($result <= 0) {
250
			$error++;
251
		}
252
253
		// Insert lines in mrp_production table
254
		if (! $error && $this->fk_bom > 0)
255
		{
256
			include_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
257
			$bom = new Bom($this->db);
258
			$bom->fetch($this->fk_bom);
259
			if ($bom->id > 0)
260
			{
261
				foreach($bom->lines as $line)
262
				{
263
					$moline = new MoLine($this->db);
264
265
					$moline->fk_mo = $this->id;
266
					$moline->qty = $line->qty * $this->qty * $bom->efficiency;
267
					if ($moline->qty <= 0) {
268
						$error++;
269
						$this->error = "BadValueForquantityToConsume";
270
						break;
271
					}
272
					else {
273
						$moline->fk_product = $line->fk_product;
274
						$moline->role = 'toconsume';
275
						$moline->position = $line->position;
276
						$moline->qty_frozen = $line->qty_frozen;
277
						$moline->disable_stock_change = $line->disable_stock_change;
278
279
						$resultline = $moline->create($user);
280
						if ($resultline <= 0) {
281
							$error++;
282
							$this->error = $moline->error;
283
							$this->errors = $moline->errors;
284
							dol_print_error($this->db, $moline->error, $moline->errors);
285
							break;
286
						}
287
					}
288
				}
289
			}
290
		}
291
292
		if (! $error) {
293
			$this->db->commit();
294
		} else {
295
			$this->db->rollback();
296
		}
297
298
		return $result;
299
	}
300
301
	/**
302
	 * Clone an object into another one
303
	 *
304
	 * @param  	User 	$user      	User that creates
305
	 * @param  	int 	$fromid     Id of object to clone
306
	 * @return 	mixed 				New object created, <0 if KO
307
	 */
308
	public function createFromClone(User $user, $fromid)
309
	{
310
		global $langs, $extrafields;
311
	    $error = 0;
312
313
	    dol_syslog(__METHOD__, LOG_DEBUG);
314
315
	    $object = new self($this->db);
316
317
	    $this->db->begin();
318
319
	    // Load source object
320
	    $result = $object->fetchCommon($fromid);
321
	    if ($result > 0 && !empty($object->table_element_line)) $object->fetchLines();
322
323
	    // get lines so they will be clone
324
	    //foreach($this->lines as $line)
325
	    //	$line->fetch_optionals();
326
327
	    // Reset some properties
328
	    unset($object->id);
329
	    unset($object->fk_user_creat);
330
	    unset($object->import_key);
331
332
	    // Clear fields
333
	    $object->ref = empty($this->fields['ref']['default']) ? "copy_of_".$object->ref : $this->fields['ref']['default'];
334
	    $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
335
	    $object->status = self::STATUS_DRAFT;
336
	    // ...
337
	    // Clear extrafields that are unique
338
	    if (is_array($object->array_options) && count($object->array_options) > 0)
339
	    {
340
	    	$extrafields->fetch_name_optionals_label($this->table_element);
341
	    	foreach ($object->array_options as $key => $option)
342
	    	{
343
	    		$shortkey = preg_replace('/options_/', '', $key);
344
	    		if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey]))
345
	    		{
346
	    			//var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
347
	    			unset($object->array_options[$key]);
348
	    		}
349
	    	}
350
	    }
351
352
	    // Create clone
353
		$object->context['createfromclone'] = 'createfromclone';
354
	    $result = $object->createCommon($user);
355
	    if ($result < 0) {
356
	        $error++;
357
	        $this->error = $object->error;
358
	        $this->errors = $object->errors;
359
	    }
360
361
	    if (!$error)
362
	    {
363
	    	// copy internal contacts
364
	    	if ($this->copy_linked_contact($object, 'internal') < 0)
365
	    	{
366
	    		$error++;
367
	    	}
368
	    }
369
370
	    if (!$error)
371
	    {
372
	    	// copy external contacts if same company
373
	    	if (property_exists($this, 'socid') && $this->socid == $object->socid)
1 ignored issue
show
Bug Best Practice introduced by
The property socid does not exist on Mo. Did you maybe forget to declare it?
Loading history...
374
	    	{
375
	    		if ($this->copy_linked_contact($object, 'external') < 0)
376
	    			$error++;
377
	    	}
378
	    }
379
380
	    unset($object->context['createfromclone']);
381
382
	    // End
383
	    if (!$error) {
384
	        $this->db->commit();
385
	        return $object;
386
	    } else {
387
	        $this->db->rollback();
388
	        return -1;
389
	    }
390
	}
391
392
	/**
393
	 * Load object in memory from the database
394
	 *
395
	 * @param int    $id   Id object
396
	 * @param string $ref  Ref
397
	 * @return int         <0 if KO, 0 if not found, >0 if OK
398
	 */
399
	public function fetch($id, $ref = null)
400
	{
401
		$result = $this->fetchCommon($id, $ref);
402
		if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
403
		return $result;
404
	}
405
406
	/**
407
	 * Load object lines in memory from the database
408
	 *
409
	 * @return int         <0 if KO, 0 if not found, >0 if OK
410
	 */
411
	public function fetchLines()
412
	{
413
		$this->lines = array();
414
415
		$result = $this->fetchLinesCommon();
416
		return $result;
417
	}
418
419
420
	/**
421
	 * Load list of objects in memory from the database.
422
	 *
423
	 * @param  string      $sortorder    Sort Order
424
	 * @param  string      $sortfield    Sort field
425
	 * @param  int         $limit        limit
426
	 * @param  int         $offset       Offset
427
	 * @param  array       $filter       Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
428
	 * @param  string      $filtermode   Filter mode (AND or OR)
429
	 * @return array|int                 int <0 if KO, array of pages if OK
430
	 */
431
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
432
	{
433
		global $conf;
434
435
		dol_syslog(__METHOD__, LOG_DEBUG);
436
437
		$records = array();
438
439
		$sql = 'SELECT ';
440
		$sql .= $this->getFieldList();
441
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
442
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
443
		else $sql .= ' WHERE 1 = 1';
444
		// Manage filter
445
		$sqlwhere = array();
446
		if (count($filter) > 0) {
447
			foreach ($filter as $key => $value) {
448
				if ($key == 't.rowid') {
449
					$sqlwhere[] = $key.'='.$value;
450
				}
451
				elseif (strpos($key, 'date') !== false) {
452
					$sqlwhere[] = $key.' = \''.$this->db->idate($value).'\'';
453
				}
454
				elseif ($key == 'customsql') {
455
					$sqlwhere[] = $value;
456
				}
457
				else {
458
					$sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\'';
459
				}
460
			}
461
		}
462
		if (count($sqlwhere) > 0) {
463
			$sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')';
464
		}
465
466
		if (!empty($sortfield)) {
467
			$sql .= $this->db->order($sortfield, $sortorder);
468
		}
469
		if (!empty($limit)) {
470
			$sql .= ' '.$this->db->plimit($limit, $offset);
471
		}
472
473
		$resql = $this->db->query($sql);
474
		if ($resql) {
475
			$num = $this->db->num_rows($resql);
476
            $i = 0;
477
			while ($i < min($limit, $num))
478
			{
479
			    $obj = $this->db->fetch_object($resql);
480
481
				$record = new self($this->db);
482
				$record->setVarsFromFetchObj($obj);
483
484
				$records[$record->id] = $record;
485
486
				$i++;
487
			}
488
			$this->db->free($resql);
489
490
			return $records;
491
		} else {
492
			$this->errors[] = 'Error '.$this->db->lasterror();
493
			dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
494
495
			return -1;
496
		}
497
	}
498
499
	/**
500
	 * Update object into database
501
	 *
502
	 * @param  User $user      User that modifies
503
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
504
	 * @return int             <0 if KO, >0 if OK
505
	 */
506
	public function update(User $user, $notrigger = false)
507
	{
508
		return $this->updateCommon($user, $notrigger);
509
	}
510
511
	/**
512
	 * Delete object in database
513
	 *
514
	 * @param User $user       User that deletes
515
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
516
	 * @return int             <0 if KO, >0 if OK
517
	 */
518
	public function delete(User $user, $notrigger = false)
519
	{
520
		return $this->deleteCommon($user, $notrigger);
521
		//return $this->deleteCommon($user, $notrigger, 1);
522
	}
523
524
	/**
525
	 *  Delete a line of object in database
526
	 *
527
	 *	@param  User	$user       User that delete
528
	 *  @param	int		$idline		Id of line to delete
529
	 *  @param 	bool 	$notrigger  false=launch triggers after, true=disable triggers
530
	 *  @return int         		>0 if OK, <0 if KO
531
	 */
532
	public function deleteLine(User $user, $idline, $notrigger = false)
533
	{
534
		if ($this->status < 0)
535
		{
536
			$this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
537
			return -2;
538
		}
539
540
		return $this->deleteLineCommon($user, $idline, $notrigger);
541
	}
542
543
    /**
544
     *  Return a link to the object card (with optionaly the picto)
545
     *
546
     *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
547
     *  @param  string  $option                     On what the link point to ('nolink', ...)
548
     *  @param  int     $notooltip                  1=Disable tooltip
549
     *  @param  string  $morecss                    Add more css on link
550
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
551
     *  @return	string                              String with URL
552
     */
553
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
554
    {
555
        global $conf, $langs, $hookmanager;
556
557
        if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips
558
559
        $result = '';
560
561
        $label = '<u>'.$langs->trans("MO").'</u>';
562
        $label .= '<br>';
563
        $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
564
565
        $url = dol_buildpath('/mrp/mo_card.php', 1).'?id='.$this->id;
566
567
        if ($option != 'nolink')
568
        {
569
            // Add param to save lastsearch_values or not
570
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
571
            if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
572
            if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
573
        }
574
575
        $linkclose = '';
576
        if (empty($notooltip))
577
        {
578
            if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
579
            {
580
                $label = $langs->trans("ShowMo");
581
                $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
582
            }
583
            $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
584
            $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
585
        }
586
        else $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
587
588
		$linkstart = '<a href="'.$url.'"';
589
		$linkstart .= $linkclose.'>';
590
		$linkend = '</a>';
591
592
		$result .= $linkstart;
593
		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);
594
		if ($withpicto != 2) $result .= $this->ref;
595
		$result .= $linkend;
596
		//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
597
598
		global $action, $hookmanager;
599
		$hookmanager->initHooks(array('modao'));
600
		$parameters = array('id'=>$this->id, 'getnomurl'=>$result);
601
		$reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
602
		if ($reshook > 0) $result = $hookmanager->resPrint;
603
		else $result .= $hookmanager->resPrint;
604
605
		return $result;
606
    }
607
608
	/**
609
	 *  Return label of the status
610
	 *
611
	 *  @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
612
	 *  @return	string 			       Label of status
613
	 */
614
	public function getLibStatut($mode = 0)
615
	{
616
		return $this->LibStatut($this->status, $mode);
617
	}
618
619
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
620
	/**
621
	 *  Return the status
622
	 *
623
	 *  @param	int		$status        Id status
624
	 *  @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
625
	 *  @return string 			       Label of status
626
	 */
627
	public function LibStatut($status, $mode = 0)
628
	{
629
		// phpcs:enable
630
		if (empty($this->labelStatus))
631
		{
632
			global $langs;
633
			//$langs->load("mrp");
634
			$this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft');
635
			$this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Validated');
636
			$this->labelStatus[self::STATUS_INPROGRESS] = $langs->trans('InProgress');
637
			$this->labelStatus[self::STATUS_PRODUCED] = $langs->trans('StatusMOProduced');
638
			$this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Canceled');
639
		}
640
641
		$statusType = 'status'.$status;
642
		//if ($status == self::STATUS_VALIDATED) $statusType = 'status4';
643
644
		return dolGetStatus($this->labelStatus[$status], $this->labelStatus[$status], '', $statusType, $mode);
645
	}
646
647
	/**
648
	 *	Load the info information in the object
649
	 *
650
	 *	@param  int		$id       Id of object
651
	 *	@return	void
652
	 */
653
	public function info($id)
654
	{
655
		$sql = 'SELECT rowid, date_creation as datec, tms as datem,';
656
		$sql .= ' fk_user_creat, fk_user_modif';
657
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
658
		$sql .= ' WHERE t.rowid = '.$id;
659
		$result = $this->db->query($sql);
660
		if ($result)
661
		{
662
			if ($this->db->num_rows($result))
663
			{
664
				$obj = $this->db->fetch_object($result);
665
				$this->id = $obj->rowid;
666
				if ($obj->fk_user_author)
667
				{
668
					$cuser = new User($this->db);
669
					$cuser->fetch($obj->fk_user_author);
670
					$this->user_creation = $cuser;
671
				}
672
673
				if ($obj->fk_user_valid)
674
				{
675
					$vuser = new User($this->db);
676
					$vuser->fetch($obj->fk_user_valid);
677
					$this->user_validation = $vuser;
678
				}
679
680
				if ($obj->fk_user_cloture)
681
				{
682
					$cluser = new User($this->db);
683
					$cluser->fetch($obj->fk_user_cloture);
684
					$this->user_cloture = $cluser;
685
				}
686
687
				$this->date_creation     = $this->db->jdate($obj->datec);
688
				$this->date_modification = $this->db->jdate($obj->datem);
689
				$this->date_validation   = $this->db->jdate($obj->datev);
690
			}
691
692
			$this->db->free($result);
693
		}
694
		else
695
		{
696
			dol_print_error($this->db);
697
		}
698
	}
699
700
	/**
701
	 * Initialise object with example values
702
	 * Id must be 0 if object instance is a specimen
703
	 *
704
	 * @return void
705
	 */
706
	public function initAsSpecimen()
707
	{
708
		$this->initAsSpecimenCommon();
709
	}
710
711
	/**
712
	 * 	Create an array of lines
713
	 *
714
	 * 	@return array|int		array of lines if OK, <0 if KO
715
	 */
716
	public function getLinesArray()
717
	{
718
	    $this->lines = array();
719
720
	    $objectline = new MoLine($this->db);
721
	    $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_mo = '.$this->id));
722
723
	    if (is_numeric($result))
1 ignored issue
show
introduced by
The condition is_numeric($result) is always true.
Loading history...
724
	    {
725
	        $this->error = $this->error;
726
	        $this->errors = $this->errors;
727
	        return $result;
728
	    }
729
	    else
730
	    {
731
	        $this->lines = $result;
732
	        return $this->lines;
733
	    }
734
	}
735
736
	/**
737
	 *  Create a document onto disk according to template module.
738
	 *
739
	 *  @param	    string		$modele			Force template to use ('' to not force)
740
	 *  @param		Translate	$outputlangs	objet lang a utiliser pour traduction
741
	 *  @param      int			$hidedetails    Hide details of lines
742
	 *  @param      int			$hidedesc       Hide description
743
	 *  @param      int			$hideref        Hide ref
744
	 *  @param      null|array  $moreparams     Array to provide more information
745
	 *  @return     int         				0 if KO, 1 if OK
746
	 */
747
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
748
	{
749
		global $conf, $langs;
750
751
		$langs->load("mrp");
752
753
		if (!dol_strlen($modele)) {
754
			$modele = 'standard';
755
756
			if ($this->modelpdf) {
757
				$modele = $this->modelpdf;
758
			} elseif (!empty($conf->global->MO_ADDON_PDF)) {
759
				$modele = $conf->global->MO_ADDON_PDF;
760
			}
761
		}
762
763
		$modelpath = "core/modules/mrp/doc/";
764
765
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
766
	}
767
768
	/**
769
	 * Action executed by scheduler
770
	 * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters'
771
	 *
772
	 * @return	int			0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
773
	 */
774
	//public function doScheduledJob($param1, $param2, ...)
775
	public function doScheduledJob()
776
	{
777
		global $conf, $langs;
778
779
		//$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
780
781
		$error = 0;
782
		$this->output = '';
783
		$this->error = '';
784
785
		dol_syslog(__METHOD__, LOG_DEBUG);
786
787
		$now = dol_now();
788
789
		$this->db->begin();
790
791
		// ...
792
793
		$this->db->commit();
794
795
		return $error;
796
	}
797
798
	/**
799
	 * 	Return HTML table table of source object lines
800
	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
801
	 *  If lines are into a template, title must also be into a template
802
	 *  But for the moment we don't know if it's possible, so we keep the method available on overloaded objects.
803
	 *
804
	 *	@param	string		$restrictlist		''=All lines, 'services'=Restrict to services only
805
	 *  @param  array       $selectedLines      Array of lines id for selected lines
806
	 *  @return	void
807
	 */
808
	public function printOriginLinesList($restrictlist = '', $selectedLines = array())
809
	{
810
		global $langs, $hookmanager, $conf, $form;
811
812
		print '<tr class="liste_titre">';
813
		print '<td>'.$langs->trans('Ref').'</td>';
814
		print '<td class="right">'.$langs->trans('Qty').'</td>';
815
		print '<td class="center">'.$langs->trans('QtyFrozen').'</td>';
816
		print '<td class="center">'.$langs->trans('DisableStockChange').'</td>';
817
		//print '<td class="right">'.$langs->trans('Efficiency').'</td>';
818
		//print '<td class="center">'.$form->showCheckAddButtons('checkforselect', 1).'</td>';
819
		print '<td class="center"></td>';
820
		print '</tr>';
821
		$i	 = 0;
822
823
		if (! empty($this->lines))
824
		{
825
			foreach ($this->lines as $line)
826
			{
827
				if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line)))
0 ignored issues
show
Bug introduced by
The property product_type does not exist on MoLine. Did you mean product?
Loading history...
828
				{
829
					if (empty($line->fk_parent_line))
830
					{
831
						$parameters=array('line'=>$line, 'i'=>$i);
832
						$action='';
833
						$hookmanager->executeHooks('printOriginObjectLine', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
834
					}
835
				}
836
				else
837
				{
838
					$this->printOriginLine($line, '', $restrictlist, '/core/tpl', $selectedLines);
839
				}
840
841
				$i++;
842
			}
843
		}
844
	}
845
846
847
	/**
848
	 * 	Return HTML with a line of table array of source object lines
849
	 *  TODO Move this and previous function into output html class file (htmlline.class.php).
850
	 *  If lines are into a template, title must also be into a template
851
	 *  But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
852
	 *
853
	 * 	@param	CommonObjectLine	$line				Line
854
	 * 	@param	string				$var				Var
855
	 *	@param	string				$restrictlist		''=All lines, 'services'=Restrict to services only (strike line if not)
856
	 *  @param	string				$defaulttpldir		Directory where to find the template
857
	 *  @param  array       		$selectedLines      Array of lines id for selected lines
858
	 * 	@return	void
859
	 */
860
	public function printOriginLine($line, $var, $restrictlist = '', $defaulttpldir = '/core/tpl', $selectedLines = array())
861
	{
862
		global $langs, $conf;
863
864
		$this->tpl['id'] = $line->id;
865
866
		$this->tpl['label']='';
867
		if (! empty($line->fk_product))
868
		{
869
			$productstatic = new Product($this->db);
870
			$productstatic->fetch($line->fk_product);
871
			$this->tpl['label'].= $productstatic->getNomUrl(1);
872
			//$this->tpl['label'].= ' - '.$productstatic->label;
873
		}
874
		else
875
		{
876
			// If origin BOM line is not a product, but another BOM
877
			// TODO
878
		}
879
880
		$this->tpl['qty'] = $line->qty;
881
		$this->tpl['qty_frozen'] = $line->qty_frozen;
882
		$this->tpl['disable_stock_change'] = $line->disable_stock_change;
883
		//$this->tpl['efficiency'] = $line->efficiency;
884
885
		$tpl = DOL_DOCUMENT_ROOT.'/mrp/tpl/originproductline.tpl.php';
886
		$res = include $tpl;
887
	}
888
}
889
890
/**
891
 * Class MoLine. You can also remove this and generate a CRUD class for lines objects.
892
 */
893
class MoLine extends CommonObjectLine
894
{
895
	/**
896
	 * @var string ID to identify managed object
897
	 */
898
	public $element = 'mrp_production';
899
900
	/**
901
	 * @var string Name of table without prefix where object is stored
902
	 */
903
	public $table_element = 'mrp_production';
904
905
	/**
906
	 * @var int  Does myobject support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
907
	 */
908
	public $ismultientitymanaged = 0;
909
910
	/**
911
	 * @var int  Does moline support extrafields ? 0=No, 1=Yes
912
	 */
913
	public $isextrafieldmanaged = 0;
914
915
	public $fields=array(
916
		'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
917
		'fk_mo' =>array('type'=>'integer', 'label'=>'Fk mo', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>15),
918
		'position' =>array('type'=>'integer', 'label'=>'Position', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>20),
919
		'fk_product' =>array('type'=>'integer', 'label'=>'Fk product', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25),
920
		'fk_warehouse' =>array('type'=>'integer', 'label'=>'Fk warehouse', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
921
		'qty' =>array('type'=>'integer', 'label'=>'Qty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
922
		'qty_frozen' => array('type'=>'smallint', 'label'=>'QuantityFrozen', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>105, 'css'=>'maxwidth50imp', 'help'=>'QuantityConsumedInvariable'),
923
		'disable_stock_change' => array('type'=>'smallint', 'label'=>'DisableStockChange', 'enabled'=>1, 'visible'=>1, 'default'=>0, 'position'=>108, 'css'=>'maxwidth50imp', 'help'=>'DisableStockChangeHelp'),
924
		'batch' =>array('type'=>'varchar(30)', 'label'=>'Batch', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
925
		'role' =>array('type'=>'varchar(10)', 'label'=>'Role', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
926
		'fk_mrp_production' =>array('type'=>'integer', 'label'=>'Fk mrp production', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
927
		'fk_stock_movement' =>array('type'=>'integer', 'label'=>'Fk stock movement', 'enabled'=>1, 'visible'=>-1, 'position'=>155),
928
		'date_creation' =>array('type'=>'datetime', 'label'=>'Date creation', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>160),
929
		'tms' =>array('type'=>'timestamp', 'label'=>'Tms', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>165),
930
		'fk_user_creat' =>array('type'=>'integer', 'label'=>'Fk user creat', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>170),
931
		'fk_user_modif' =>array('type'=>'integer', 'label'=>'Fk user modif', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
932
		'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportKey', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
933
	);
934
935
	public $rowid;
936
	public $fk_mo;
937
	public $position;
938
	public $fk_product;
939
	public $fk_warehouse;
940
	public $qty;
941
	public $qty_frozen;
942
	public $disable_stock_change;
943
	public $batch;
944
	public $role;
945
	public $fk_mrp_production;
946
	public $fk_stock_movement;
947
	public $date_creation;
948
	public $tms;
949
	public $fk_user_creat;
950
	public $fk_user_modif;
951
	public $import_key;
952
953
	/**
954
	 * Constructor
955
	 *
956
	 * @param DoliDb $db Database handler
957
	 */
958
	public function __construct(DoliDB $db)
959
	{
960
		global $conf, $langs;
961
962
		$this->db = $db;
963
964
		if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) $this->fields['rowid']['visible'] = 0;
965
		if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) $this->fields['entity']['enabled'] = 0;
966
967
		// Unset fields that are disabled
968
		foreach ($this->fields as $key => $val)
969
		{
970
			if (isset($val['enabled']) && empty($val['enabled']))
971
			{
972
				unset($this->fields[$key]);
973
			}
974
		}
975
976
		// Translate some data of arrayofkeyval
977
		if (is_object($langs))
978
		{
979
			foreach($this->fields as $key => $val)
980
			{
981
				if (is_array($val['arrayofkeyval']))
982
				{
983
					foreach($val['arrayofkeyval'] as $key2 => $val2)
984
					{
985
						$this->fields[$key]['arrayofkeyval'][$key2]=$langs->trans($val2);
986
					}
987
				}
988
			}
989
		}
990
	}
991
992
	/**
993
	 * Create object into database
994
	 *
995
	 * @param  User $user      User that creates
996
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
997
	 * @return int             <0 if KO, Id of created object if OK
998
	 */
999
	public function create(User $user, $notrigger = false)
1000
	{
1001
		return $this->createCommon($user, $notrigger);
1002
	}
1003
1004
	/**
1005
	 * Load object in memory from the database
1006
	 *
1007
	 * @param int    $id   Id object
1008
	 * @param string $ref  Ref
1009
	 * @return int         <0 if KO, 0 if not found, >0 if OK
1010
	 */
1011
	public function fetch($id, $ref = null)
1012
	{
1013
		$result = $this->fetchCommon($id, $ref);
1014
		if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
0 ignored issues
show
Bug introduced by
The method fetchLines() does not exist on MoLine. Did you maybe mean fetchLinesCommon()? ( Ignorable by Annotation )

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

1014
		if ($result > 0 && !empty($this->table_element_line)) $this->/** @scrutinizer ignore-call */ fetchLines();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1015
		return $result;
1016
	}
1017
1018
	/**
1019
	 * Load list of objects in memory from the database.
1020
	 *
1021
	 * @param  string      $sortorder    Sort Order
1022
	 * @param  string      $sortfield    Sort field
1023
	 * @param  int         $limit        limit
1024
	 * @param  int         $offset       Offset
1025
	 * @param  array       $filter       Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
1026
	 * @param  string      $filtermode   Filter mode (AND or OR)
1027
	 * @return array|int                 int <0 if KO, array of pages if OK
1028
	 */
1029
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
1030
	{
1031
		global $conf;
1032
1033
		dol_syslog(__METHOD__, LOG_DEBUG);
1034
1035
		$records = array();
1036
1037
		$sql = 'SELECT ';
1038
		$sql .= $this->getFieldList();
1039
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
1040
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) $sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
1041
		else $sql .= ' WHERE 1 = 1';
1042
		// Manage filter
1043
		$sqlwhere = array();
1044
		if (count($filter) > 0) {
1045
			foreach ($filter as $key => $value) {
1046
				if ($key == 't.rowid') {
1047
					$sqlwhere[] = $key.'='.$value;
1048
				}
1049
				elseif (strpos($key, 'date') !== false) {
1050
					$sqlwhere[] = $key.' = \''.$this->db->idate($value).'\'';
1051
				}
1052
				elseif ($key == 'customsql') {
1053
					$sqlwhere[] = $value;
1054
				}
1055
				else {
1056
					$sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\'';
1057
				}
1058
			}
1059
		}
1060
		if (count($sqlwhere) > 0) {
1061
			$sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')';
1062
		}
1063
1064
		if (!empty($sortfield)) {
1065
			$sql .= $this->db->order($sortfield, $sortorder);
1066
		}
1067
		if (!empty($limit)) {
1068
			$sql .= ' '.$this->db->plimit($limit, $offset);
1069
		}
1070
1071
		$resql = $this->db->query($sql);
1072
		if ($resql) {
1073
			$num = $this->db->num_rows($resql);
1074
			$i = 0;
1075
			while ($i < min($limit, $num))
1076
			{
1077
				$obj = $this->db->fetch_object($resql);
1078
1079
				$record = new self($this->db);
1080
				$record->setVarsFromFetchObj($obj);
1081
1082
				$records[$record->id] = $record;
1083
1084
				$i++;
1085
			}
1086
			$this->db->free($resql);
1087
1088
			return $records;
1089
		} else {
1090
			$this->errors[] = 'Error '.$this->db->lasterror();
1091
			dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
1092
1093
			return -1;
1094
		}
1095
	}
1096
1097
	/**
1098
	 * Update object into database
1099
	 *
1100
	 * @param  User $user      User that modifies
1101
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
1102
	 * @return int             <0 if KO, >0 if OK
1103
	 */
1104
	public function update(User $user, $notrigger = false)
1105
	{
1106
		return $this->updateCommon($user, $notrigger);
1107
	}
1108
1109
	/**
1110
	 * Delete object in database
1111
	 *
1112
	 * @param User $user       User that deletes
1113
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
1114
	 * @return int             <0 if KO, >0 if OK
1115
	 */
1116
	public function delete(User $user, $notrigger = false)
1117
	{
1118
		return $this->deleteCommon($user, $notrigger);
1119
		//return $this->deleteCommon($user, $notrigger, 1);
1120
	}
1121
}
1122