dolibarr  13.0.2
inventory.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2007-2019 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2014-2016 Juanjo Menent <jmenent@2byte.es>
4  * Copyright (C) 2015 Florian Henry <florian.henry@open-concept.pro>
5  * Copyright (C) 2015 RaphaĆ«l Doursenaud <rdoursenaud@gpcsolutions.fr>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
27 // Put here all includes required by your class file
28 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29 //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
30 //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
31 
35 class Inventory extends CommonObject
36 {
40  public $element = 'inventory';
41 
45  public $table_element = 'inventory';
46 
50  public $ismultientitymanaged = 1;
51 
55  public $isextrafieldmanaged = 1;
56 
60  public $picto = 'stock';
61 
62  const STATUS_DRAFT = 0;
63  const STATUS_VALIDATED = 1;
64  const STATUS_RECORDED = 2;
65  const STATUS_CANCELED = 9;
66 
88  // BEGIN MODULEBUILDER PROPERTIES
92  public $fields = array(
93  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-1, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>'Id',),
94  'ref' => array('type'=>'varchar(64)', 'label'=>'Ref', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>'Reference of object', 'css'=>'maxwidth200'),
95  'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
96  'title' => array('type'=>'varchar(255)', 'label'=>'Label', 'visible'=>1, 'enabled'=>1, 'position'=>25, 'css'=>'minwidth300'),
97  'fk_warehouse' => array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php', 'label'=>'Warehouse', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'index'=>1, 'help'=>'InventoryForASpecificWarehouse'),
98  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'visible'=>1, 'enabled'=>1, 'position'=>32, 'index'=>1, 'help'=>'InventoryForASpecificProduct'),
99  'date_inventory' => array('type'=>'date', 'label'=>'DateValue', 'visible'=>1, 'enabled'=>1, 'position'=>35),
100 
101  'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>500),
102  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>501),
103  'date_validation' => array('type'=>'datetime', 'label'=>'DateValidation', 'visible'=>-2, 'enabled'=>1, 'position'=>502),
104  'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>510, 'foreignkey'=>'user.rowid'),
105  'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>511),
106  'fk_user_valid' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'visible'=>-2, 'enabled'=>1, 'position'=>512),
107  'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'position'=>1000),
108 
109  'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>4, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'default'=>0, 'index'=>1, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 2=>'Recorded', 9=>'Canceled'))
110  );
111 
115  public $rowid;
116 
120  public $ref;
121 
125  public $entity;
126 
130  public $fk_warehouse;
131 
135  public $fk_product;
136 
137  public $date_inventory;
138  public $title;
139 
143  public $status;
144 
148  public $date_creation;
149 
153  public $date_validation;
154 
155 
156  public $tms;
157 
161  public $fk_user_creat;
162 
166  public $fk_user_modif;
167 
171  public $fk_user_valid;
172 
176  public $import_key;
177  // END MODULEBUILDER PROPERTIES
178 
179 
180 
181  // If this object has a subtable with lines
182 
186  public $table_element_line = 'inventorydet';
187 
191  public $fk_element = 'fk_inventory';
192 
196  public $class_element_line = 'Inventoryline';
197 
201  protected $childtables = array();
205  protected $childtablesoncascade = array('inventorydet');
206 
210  public $lines = array();
211 
212 
213 
219  public function __construct(DoliDB $db)
220  {
221  global $conf;
222 
223  $this->db = $db;
224 
225  if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID)) $this->fields['rowid']['visible'] = 0;
226  if (empty($conf->multicompany->enabled)) $this->fields['entity']['enabled'] = 0;
227  }
228 
229 
237  public function create(User $user, $notrigger = false)
238  {
239  $result = $this->createCommon($user, $notrigger);
240 
241  return $result;
242  }
243 
251  public function validate(User $user, $notrigger = false)
252  {
253  $this->db->begin();
254 
255  $result = 0;
256 
257  if ($this->status == self::STATUS_DRAFT) {
258  // Delete inventory
259  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'inventorydet WHERE fk_inventory = '.$this->id;
260  $resql = $this->db->query($sql);
261  if (!$resql) {
262  $this->error = $this->db->lasterror();
263  $this->db->rollback();
264  return -1;
265  }
266 
267  // Scan existing stock to prefill the inventory
268  $sql = 'SELECT ps.rowid, ps.fk_entrepot as fk_warehouse, ps.fk_product, ps.reel,';
269  $sql .= ' pb.batch, pb.qty';
270  $sql .= ' FROM '.MAIN_DB_PREFIX.'product_stock as ps';
271  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_batch as pb ON pb.fk_product_stock = ps.rowid,';
272  $sql .= ' '.MAIN_DB_PREFIX.'product as p, '.MAIN_DB_PREFIX.'entrepot as e';
273  $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
274  $sql .= ' AND ps.fk_product = p.rowid AND ps.fk_entrepot = e.rowid';
275  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) $sql .= " AND p.fk_product_type = 0";
276  if ($this->fk_product > 0) $sql .= ' AND ps.fk_product = '.$this->fk_product;
277  if ($this->fk_warehouse > 0) $sql .= ' AND ps.fk_entrepot = '.$this->fk_warehouse;
278 
279  $inventoryline = new InventoryLine($this->db);
280 
281  $resql = $this->db->query($sql);
282  if ($resql)
283  {
284  $num = $this->db->num_rows($resql);
285 
286  $i = 0;
287  while ($i < $num)
288  {
289  $obj = $this->db->fetch_object($resql);
290 
291  $inventoryline->fk_inventory = $this->id;
292  $inventoryline->fk_warehouse = $obj->fk_warehouse;
293  $inventoryline->fk_product = $obj->fk_product;
294  $inventoryline->batch = $obj->batch;
295  $inventoryline->qty_stock = ($obj->batch ? $obj->qty : $obj->reel); // If there is batch detail, we take qty for batch, else global qty
296  $inventoryline->datec = dol_now();
297 
298  $resultline = $inventoryline->create($user);
299  if ($resultline <= 0) {
300  $this->error = $inventoryline->error;
301  $this->errors = $inventoryline->errors;
302  $result = -1;
303  break;
304  }
305 
306  $i++;
307  }
308  } else {
309  $result = -1;
310  $this->error = $this->db->lasterror();
311  }
312  }
313 
314  if ($result >= 0) {
315  $result = $this->setStatut($this::STATUS_VALIDATED, null, '', 'INVENTORY_VALIDATED');
316  }
317 
318  if ($result > 0) {
319  $this->db->commit();
320  } else {
321  $this->db->rollback();
322  }
323  }
324 
332  public function setDraft(User $user, $notrigger = false)
333  {
334  $this->db->begin();
335 
336  // Delete inventory
337  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'inventorydet WHERE fk_inventory = '.$this->id;
338  $resql = $this->db->query($sql);
339  if (!$resql) {
340  $this->error = $this->db->lasterror();
341  $this->db->rollback();
342  return -1;
343  }
344 
345  $result = $this->setStatut($this::STATUS_DRAFT, null, '', 'INVENTORY_DRAFT');
346 
347  if ($result > 0) {
348  $this->db->commit();
349  } else {
350  $this->db->rollback();
351  }
352  }
353 
361  public function createFromClone(User $user, $fromid)
362  {
363  global $hookmanager, $langs;
364  $error = 0;
365 
366  dol_syslog(__METHOD__, LOG_DEBUG);
367 
368  $object = new self($this->db);
369 
370  $this->db->begin();
371 
372  // Load source object
373  $object->fetchCommon($fromid);
374  // Reset some properties
375  unset($object->id);
376  unset($object->fk_user_creat);
377  unset($object->import_key);
378 
379  // Clear fields
380  $object->ref = "copy_of_".$object->ref;
381  $object->title = $langs->trans("CopyOf")." ".$object->title;
382  // ...
383 
384  // Create clone
385  $object->context['createfromclone'] = 'createfromclone';
386  $result = $object->createCommon($user);
387  if ($result < 0) {
388  $error++;
389  $this->error = $object->error;
390  $this->errors = $object->errors;
391  }
392 
393  unset($object->context['createfromclone']);
394 
395  // End
396  if (!$error) {
397  $this->db->commit();
398  return $object;
399  } else {
400  $this->db->rollback();
401  return -1;
402  }
403  }
404 
412  public function fetch($id, $ref = null)
413  {
414  $result = $this->fetchCommon($id, $ref);
415  //if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines();
416  return $result;
417  }
418 
424  /*public function fetchLines()
425  {
426  $this->lines=array();
427 
428  // Load lines with object MyObjectLine
429 
430  return count($this->lines)?1:0;
431  }*/
432 
440  public function update(User $user, $notrigger = false)
441  {
442  return $this->updateCommon($user, $notrigger);
443  }
444 
452  public function delete(User $user, $notrigger = false)
453  {
454  return $this->deleteCommon($user, $notrigger);
455  }
456 
465  public function deleteLine(User $user, $idline, $notrigger = false)
466  {
467  if ($this->status < 0)
468  {
469  $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
470  return -2;
471  }
472 
473  return $this->deleteLineCommon($user, $idline, $notrigger);
474  }
475 
486  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
487  {
488  global $db, $conf, $langs;
489  global $dolibarr_main_authentication, $dolibarr_main_demo;
490  global $menumanager;
491 
492  if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips
493 
494  $result = '';
495  $companylink = '';
496 
497  $label = '<u>'.$langs->trans("Inventory").'</u>';
498  $label .= '<br>';
499  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
500 
501  $url = dol_buildpath('/product/inventory/card.php', 1).'?id='.$this->id;
502 
503  $linkclose = '';
504  if (empty($notooltip))
505  {
506  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
507  {
508  $label = $langs->trans("ShowInventory");
509  $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
510  }
511  $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
512  $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
513  } else $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
514 
515  $linkstart = '<a href="'.$url.'"';
516  $linkstart .= $linkclose.'>';
517  $linkend = '</a>';
518 
519  $result .= $linkstart;
520  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);
521  if ($withpicto != 2) $result .= $this->ref;
522  $result .= $linkend;
523  //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
524 
525  return $result;
526  }
527 
534  public function getLibStatut($mode = 0)
535  {
536  return $this->LibStatut($this->status, $mode);
537  }
538 
539  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
547  public static function LibStatut($status, $mode = 0)
548  {
549  // phpcs:enable
550  global $langs;
551 
552  $labelStatus = array();
553  $labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft');
554  $labelStatus[self::STATUS_VALIDATED] = $langs->trans('Validated').' ('.$langs->trans('Started').')';
555  $labelStatus[self::STATUS_CANCELED] = $langs->trans('Canceled');
556  $labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft');
557  $labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Started');
558  $labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Canceled');
559 
560  return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', 'status'.$status, $mode);
561  }
562 
569  public function info($id)
570  {
571  $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
572  $sql .= ' fk_user_creat, fk_user_modif';
573  $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
574  $sql .= ' WHERE t.rowid = '.$id;
575  $result = $this->db->query($sql);
576  if ($result)
577  {
578  if ($this->db->num_rows($result))
579  {
580  $obj = $this->db->fetch_object($result);
581  $this->id = $obj->rowid;
582  if ($obj->fk_user_author)
583  {
584  $cuser = new User($this->db);
585  $cuser->fetch($obj->fk_user_author);
586  $this->user_creation = $cuser;
587  }
588 
589  if ($obj->fk_user_valid)
590  {
591  $vuser = new User($this->db);
592  $vuser->fetch($obj->fk_user_valid);
593  $this->user_validation = $vuser;
594  }
595 
596  if ($obj->fk_user_cloture)
597  {
598  $cluser = new User($this->db);
599  $cluser->fetch($obj->fk_user_cloture);
600  $this->user_cloture = $cluser;
601  }
602 
603  $this->date_creation = $this->db->jdate($obj->datec);
604  $this->date_modification = $this->db->jdate($obj->datem);
605  $this->date_validation = $this->db->jdate($obj->datev);
606  }
607 
608  $this->db->free($result);
609  } else {
610  dol_print_error($this->db);
611  }
612  }
613 
620  public function initAsSpecimen()
621  {
622  $this->initAsSpecimenCommon();
623  }
624 }
625 
630 {
634  public $element = 'inventoryline';
635 
639  public $table_element = 'inventorydet';
640 
644  public $ismultientitymanaged = 0;
645 
649  public $isextrafieldmanaged = 0;
650 
654  public $picto = 'stock';
655 
673  // BEGIN MODULEBUILDER PROPERTIES
677  public $fields = array(
678  'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-1, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>'Id',),
679  'fk_inventory' => array('type'=>'integer:Inventory:product/inventory/class/inventory.class.php', 'label'=>'Inventory', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'index'=>1, 'help'=>'LinkToInventory'),
680  'fk_warehouse' => array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php', 'label'=>'Warehouse', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'index'=>1, 'help'=>'LinkToThirparty'),
681  'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'visible'=>1, 'enabled'=>1, 'position'=>32, 'index'=>1, 'help'=>'LinkToProduct'),
682  'batch' => array('type'=>'string', 'label'=>'Batch', 'visible'=>1, 'enabled'=>1, 'position'=>32, 'index'=>1, 'help'=>'LinkToProduct'),
683  'datec' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>500),
684  'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>501),
685  'qty_stock' => array('type'=>'double', 'label'=>'QtyFound', 'visible'=>1, 'enabled'=>1, 'position'=>32, 'index'=>1, 'help'=>'Qty we found/want (to define during draft edition)'),
686  'qty_view' => array('type'=>'double', 'label'=>'QtyBefore', 'visible'=>1, 'enabled'=>1, 'position'=>33, 'index'=>1, 'help'=>'Qty before (filled once movements are validated)'),
687  'qty_regulated' => array('type'=>'double', 'label'=>'QtyDelta', 'visible'=>1, 'enabled'=>1, 'position'=>34, 'index'=>1, 'help'=>'Qty aadded or removed (filled once movements are validated)'),
688  );
689 
693  public $rowid;
694 
695  public $fk_inventory;
696  public $fk_warehouse;
697  public $fk_product;
698  public $batch;
699  public $datec;
700  public $tms;
701  public $qty_stock;
702  public $qty_view;
703  public $qty_regulated;
704 
705 
713  public function create(User $user, $notrigger = false)
714  {
715  return $this->createCommon($user, $notrigger);
716  }
717 
725  public function fetch($id, $ref = null)
726  {
727  $result = $this->fetchCommon($id, $ref);
728  //if ($result > 0 && ! empty($this->table_element_line)) $this->fetchLines();
729  return $result;
730  }
731 
739  public function update(User $user, $notrigger = false)
740  {
741  return $this->updateCommon($user, $notrigger);
742  }
743 
751  public function delete(User $user, $notrigger = false)
752  {
753  return $this->deleteCommon($user, $notrigger);
754  //return $this->deleteCommon($user, $notrigger, 1);
755  }
756 }
setDraft(User $user, $notrigger=false)
Go back to draft.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
getLibStatut($mode=0)
Retourne le libelle du status d&#39;un user (actif, inactif)
info($id)
Charge les informations d&#39;ordre info dans l&#39;objet commande.
__construct(DoliDB $db)
Constructor.
fetch($id, $ref=null)
Load object in memory from the database.
create(User $user, $notrigger=false)
Create object into database.
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
foreach($object->fields as $key=> $val) if(is_array($extrafields->attributes[$object->table_element]['label'])&&count($extrafields->attributes[$object->table_element]['label']) > 0) $object fields
createFromClone(User $user, $fromid)
Clone and object into another one.
dol_now($mode= 'auto')
Return date for now.
Class to manage Dolibarr users.
Definition: user.class.php:44
Class to manage Dolibarr database access.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
createCommon(User $user, $notrigger=false)
Create object into database.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
$conf db
API class for accounts.
Definition: inc.php:54
Class for Inventory.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
validate(User $user, $notrigger=false)
Validate inventory (start it)
fetch($id, $ref=null)
Load object in memory from the database.
create(User $user, $notrigger=false)
Create object in database.
getNomUrl($withpicto=0, $option= '', $notooltip=0, $morecss= '', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
update(User $user, $notrigger=false)
Load object lines in memory from the database.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
updateCommon(User $user, $notrigger=false)
Update object into database.
static LibStatut($status, $mode=0)
Return the status.
deleteLineCommon(User $user, $idline, $notrigger=false)
Delete a line of object in database.
update(User $user, $notrigger=false)
Update object into database.
setStatut($status, $elementId=null, $elementType= '', $trigkey= '')
Set status of an object.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
Class InventoryLine.
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetStatus($statusLabel= '', $statusLabelShort= '', $html= '', $statusType= 'status0', $displayMode=0, $url= '', $params=array())
Output the badge of a status.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
fetchCommon($id, $ref=null, $morewhere= '')
Load object in memory from the database.