dolibarr 25.0.0-alpha
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 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
8 * Copyright (C) 2026 Jose Martinez <jose.martinez@pichinov.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30// Put here all includes required by your class file
31require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
33//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
34//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
35
41{
45 public $element = 'inventory';
46
50 public $table_element = 'inventory';
51
55 public $picto = 'inventory';
56
57 const STATUS_DRAFT = 0; // Draft
58 const STATUS_VALIDATED = 1; // Inventory is in process
59 const STATUS_RECORDED = 2; // Inventory is finisged. Stock movement has been recorded.
60 const STATUS_CANCELED = 9; // Canceled
61
69 const START_MODE_CURRENT = 'current';
70 const START_MODE_NONE = 'none';
71 const START_MODE_ZERO = 'zero';
72
99 // BEGIN MODULEBUILDER PROPERTIES
103 public $fields = array(
104 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'visible' => -1, 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'index' => 1, 'comment' => 'Id',),
105 'ref' => array('type' => 'varchar(64)', 'label' => 'Ref', 'visible' => 1, 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'index' => 1, 'searchall' => 1, 'comment' => 'Reference of object', 'css' => 'maxwidth150'),
106 'entity' => array('type' => 'integer', 'label' => 'Entity', 'visible' => 0, 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'index' => 1,),
107 'title' => array('type' => 'varchar(255)', 'label' => 'Label', 'visible' => 1, 'enabled' => 1, 'position' => 25, 'css' => 'minwidth300', 'csslist' => 'tdoverflowmax150', 'alwayseditable' => 1),
108 'fk_warehouse' => array('type' => 'integer:Entrepot:product/stock/class/entrepot.class.php', 'label' => 'Warehouse', 'visible' => 1, 'enabled' => 1, 'position' => 30, 'index' => 1, 'help' => 'InventoryForASpecificWarehouse', 'picto' => 'stock', 'css' => 'minwidth300 maxwidth500 widthcentpercentminusx', 'csslist' => 'tdoverflowmax150'),
109 'fk_product' => array('type' => 'integer:Product:product/class/product.class.php', 'label' => 'Product', 'get_name_url_params' => '0::0:-1:0::1', 'visible' => 1, 'enabled' => 1, 'position' => 32, 'index' => 1, 'help' => 'InventoryForASpecificProduct', 'picto' => 'product', 'css' => 'minwidth300 maxwidth500 widthcentpercentminusx', 'csslist' => 'tdoverflowmax150'),
110 'categories_product' => array('type' => 'chkbxlst:categorie:label:rowid::type=0:0:', 'label' => 'OrProductsWithCategories', 'visible' => 3, 'enabled' => 1, 'position' => 33, 'help' => '', 'picto' => 'category', 'css' => 'minwidth300 maxwidth500 widthcentpercentminusx'),
111 'date_inventory' => array('type' => 'date', 'label' => 'DateValue', 'visible' => 1, 'enabled' => 'getDolGlobalInt("STOCK_INVENTORY_ADD_A_VALUE_DATE")', 'position' => 35, 'csslist' => 'nowraponall'), // This date is not used so disabled by default.
112 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 500, 'csslist' => 'nowraponall'),
113 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 501, 'csslist' => 'nowraponall'),
114 'date_validation' => array('type' => 'datetime', 'label' => 'DateValidation', 'visible' => -2, 'enabled' => 1, 'position' => 502, 'csslist' => 'nowraponall'),
115 'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 510, 'foreignkey' => 'user.rowid', 'csslist' => 'tdoverflowmax150'),
116 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'position' => 511, 'csslist' => 'tdoverflowmax150'),
117 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'visible' => -2, 'enabled' => 1, 'position' => 512, 'csslist' => 'tdoverflowmax150'),
118 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'index' => 0, 'position' => 1000),
119 'status' => array('type' => 'integer', 'label' => 'Status', 'visible' => 4, 'enabled' => 1, 'position' => 1000, 'notnull' => 1, 'default' => '0', 'index' => 1, 'arrayofkeyval' => array(0 => 'Draft', 1 => 'Validated', 2 => 'Closed', 9 => 'Canceled'))
120 );
121
125 public $rowid;
126
130 public $ref;
131
135 public $fk_warehouse;
136
140 public $fk_product;
141
145 public $categories_product;
149 public $date_inventory;
153 public $title;
154
158 public $status;
159
163 public $fk_user_creat;
164
168 public $fk_user_modif;
169
173 public $fk_user_valid;
174
178 public $import_key;
179 // END MODULEBUILDER PROPERTIES
180
181
182
183 // If this object has a subtable with lines
184
188 public $table_element_line = 'inventorydet';
189
193 public $fk_element = 'fk_inventory';
194
198 public $class_element_line = 'Inventoryline';
199
203 protected $childtables = array();
207 protected $childtablesoncascade = array('inventorydet');
208
212 public $lines = array();
213
214
215
221 public function __construct(DoliDB $db)
222 {
223 $this->db = $db;
224
225 $this->ismultientitymanaged = 1;
226 $this->isextrafieldmanaged = 0;
227
228 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID')) {
229 $this->fields['rowid']['visible'] = 0;
230 }
231 if (!isModEnabled('multicompany')) {
232 $this->fields['entity']['enabled'] = 0;
233 }
234 }
235
236
244 public function create(User $user, $notrigger = 0)
245 {
246 $result = $this->createCommon($user, $notrigger);
247
248 return $result;
249 }
250
262 public function validate(User $user, $notrigger = 0, $include_sub_warehouse = 0, $startmode = '')
263 {
264 $this->db->begin();
265
266 $result = 0;
267
268 if (empty($startmode)) {
269 $startmode = getDolGlobalString('INVENTORY_DEFAULT_START_MODE', self::START_MODE_CURRENT);
270 }
271 if (!in_array($startmode, array(self::START_MODE_CURRENT, self::START_MODE_NONE, self::START_MODE_ZERO))) {
272 $startmode = self::START_MODE_CURRENT;
273 }
274
275 if ($this->status == self::STATUS_DRAFT) {
276 // Delete inventory
277 $sql = 'DELETE FROM '.$this->db->prefix().'inventorydet WHERE fk_inventory = '.((int) $this->id);
278 $resql = $this->db->query($sql);
279 if (!$resql) {
280 $this->error = $this->db->lasterror();
281 $this->db->rollback();
282 return -1;
283 }
284
285 if ($startmode == self::START_MODE_NONE) {
286 // Start with no line at all: they will be added manually or with a barcode scanner while counting
287 $result = $this->setStatut($this::STATUS_VALIDATED, null, '', 'INVENTORY_VALIDATED');
288 if ($result > 0) {
289 $this->db->commit();
290 } else {
291 $this->db->rollback();
292 }
293 return $result;
294 }
295
296 // Scan existing stock to prefill the inventory
297 $sql = "SELECT ps.rowid, ps.fk_entrepot as fk_warehouse, ps.fk_product, ps.reel,";
298 if (isModEnabled('productbatch')) {
299 $sql .= " COALESCE(pb.batch, '') as batch, pb.qty as qty,";
300 } else {
301 $sql .= " '' as batch, 0 as qty,";
302 }
303 $sql .= " p.ref, p.tobatch";
304 $sql .= " FROM ".$this->db->prefix()."product_stock as ps";
305 if (isModEnabled('productbatch')) {
306 $sql .= " LEFT JOIN ".$this->db->prefix()."product_batch as pb ON pb.fk_product_stock = ps.rowid";
307 }
308 $sql .= ", ".$this->db->prefix()."product as p, ".$this->db->prefix()."entrepot as e";
309 $sql .= " WHERE p.entity IN (".getEntity('product').")";
310 $sql .= " AND ps.fk_product = p.rowid AND ps.fk_entrepot = e.rowid";
311 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
312 $sql .= " AND p.fk_product_type = 0";
313 }
314 if ($this->fk_product > 0) {
315 $sql .= " AND ps.fk_product = ".((int) $this->fk_product);
316 }
317 if ($this->fk_warehouse > 0) {
318 $sql .= " AND (ps.fk_entrepot = ".((int) $this->fk_warehouse);
319 if (!empty($include_sub_warehouse) && getDolGlobalInt('INVENTORY_INCLUDE_SUB_WAREHOUSE')) {
320 $TChildWarehouses = array();
321 $this->getChildWarehouse($this->fk_warehouse, $TChildWarehouses);
322 if (!empty($TChildWarehouses)) {
323 $sql .= " OR ps.fk_entrepot IN (" . $this->db->sanitize(implode(',', $TChildWarehouses)) . ")";
324 }
325 }
326 $sql .= ')';
327 }
328 if (!empty($this->categories_product)) {
329 $sql .= " AND EXISTS (";
330 $sql .= " SELECT cp.fk_product";
331 $sql .= " FROM ".$this->db->prefix()."categorie_product AS cp";
332 $sql .= " WHERE cp.fk_product = ps.fk_product";
333 $sql .= " AND cp.fk_categorie IN (".$this->db->sanitize($this->categories_product).")";
334 $sql .= ")";
335 }
336 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
337 $sql .= " AND NOT EXISTS (";
338 $sql .= " SELECT pa.rowid";
339 $sql .= " FROM ".$this->db->prefix()."product_association as pa";
340 $sql .= " WHERE pa.fk_product_pere = ps.fk_product";
341 $sql .= ")";
342 }
343 $sql .= " ORDER BY p.rowid";
344
345 $inventoryline = new InventoryLine($this->db);
346
347 $resql = $this->db->query($sql);
348 if ($resql) {
349 $num = $this->db->num_rows($resql);
350
351 $i = 0;
352 while ($i < $num) {
353 $obj = $this->db->fetch_object($resql);
354
355 $inventoryline->fk_inventory = $this->id;
356 $inventoryline->fk_warehouse = $obj->fk_warehouse;
357 $inventoryline->fk_product = $obj->fk_product;
358 $inventoryline->batch = $obj->batch;
359 $inventoryline->datec = dol_now();
360 // With the "zero" start mode, the counted qty is preset to 0 instead of being left empty,
361 // so a product that is never counted is regulated to zero when the inventory is recorded.
362 $inventoryline->qty_view = ($startmode == self::START_MODE_ZERO) ? 0 : null;
363
364 if (isModEnabled('productbatch')) {
365 if ($obj->batch && empty($obj->tobatch)) {
366 // Bad consistency of data. The product is not a product with lot/serial but we found a stock for some lot/serial.
367 $result = -2;
368 $this->error = 'The product ID='.$obj->ref." has stock with lot/serial but is configured to not manage lot/serial. You must first fix this, this way: Set the product to have 'Management of Lot/Serial' to Yes, then set it back to 'Management of Lot/Serial to No";
369 break;
370 }
371
372 $inventoryline->qty_stock = ($obj->batch ? $obj->qty : $obj->reel); // If there is batch detail, we take qty for batch, else global qty
373 } else {
374 $inventoryline->qty_stock = $obj->reel;
375 }
376
377 $resultline = $inventoryline->create($user);
378 if ($resultline <= 0) {
379 $this->error = $inventoryline->error;
380 $this->errors = $inventoryline->errors;
381 $result = -1;
382 break;
383 }
384
385 $i++;
386 }
387 } else {
388 $result = -1;
389 $this->error = $this->db->lasterror();
390 }
391 }
392
393 if ($result >= 0) {
394 $result = $this->setStatut($this::STATUS_VALIDATED, null, '', 'INVENTORY_VALIDATED');
395 }
396
397 if ($result > 0) {
398 $this->db->commit();
399 } else {
400 $this->db->rollback();
401 }
402 return $result;
403 }
404
412 public function setDraft(User $user, $notrigger = 0)
413 {
414 $this->db->begin();
415
416 // Delete inventory
417 $sql = 'DELETE FROM '.$this->db->prefix().'inventorydet WHERE fk_inventory = '.((int) $this->id);
418 $resql = $this->db->query($sql);
419 if (!$resql) {
420 $this->error = $this->db->lasterror();
421 $this->db->rollback();
422 return -1;
423 }
424
425 $result = $this->setStatut($this::STATUS_DRAFT, null, '', 'INVENTORY_DRAFT');
426
427 if ($result > 0) {
428 $this->db->commit();
429 } else {
430 $this->db->rollback();
431 }
432 return $result;
433 }
434
442 public function setRecorded(User $user, $notrigger = 0)
443 {
444 $this->db->begin();
445
446 $result = $this->setStatut($this::STATUS_RECORDED, null, '', 'INVENTORY_RECORDED');
447
448 if ($result > 0) {
449 $this->db->commit();
450 } else {
451 $this->db->rollback();
452 return -1;
453 }
454 return $result;
455 }
456
464 public function setCanceled(User $user, $notrigger = 0)
465 {
466 $this->db->begin();
467
468 $result = $this->setStatut($this::STATUS_CANCELED, null, '', 'INVENTORY_CANCELED');
469
470 if ($result > 0) {
471 $this->db->commit();
472 } else {
473 $this->db->rollback();
474 return -1;
475 }
476 return $result;
477 }
478
486 public function createFromClone(User $user, $fromid)
487 {
488 global $langs;
489
490 $error = 0;
491
492 dol_syslog(__METHOD__, LOG_DEBUG);
493
494 $object = new self($this->db);
495
496 $this->db->begin();
497
498 // Load source object
499 $object->fetchCommon($fromid);
500 // Reset some properties
501 unset($object->id);
502 unset($object->fk_user_creat);
503 unset($object->import_key);
504
505 // Clear fields
506 $object->ref = "copy_of_".$object->ref;
507 $object->title = $langs->trans("CopyOf")." ".$object->title;
508 // ...
509
510 // Create clone
511 $object->context['createfromclone'] = 'createfromclone';
512 $result = $object->createCommon($user);
513 if ($result < 0) {
514 $error++;
516 }
517
518 unset($object->context['createfromclone']);
519
520 // End
521 if (!$error) {
522 $this->db->commit();
523 return $object;
524 } else {
525 $this->db->rollback();
526 return -1;
527 }
528 }
529
537 public function fetch($id, $ref = null)
538 {
539 $result = $this->fetchCommon($id, $ref);
540 //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
541 return $result;
542 }
543
549 /*public function fetchLines()
550 {
551 $this->lines=array();
552
553 // Load lines with object MyObjectLine
554
555 return count($this->lines)?1:0;
556 }*/
557
565 public function update(User $user, $notrigger = 0)
566 {
567 return $this->updateCommon($user, $notrigger);
568 }
569
577 public function delete(User $user, $notrigger = 0)
578 {
579 return $this->deleteCommon($user, $notrigger);
580 }
581
590 public function deleteLine(User $user, $idline, $notrigger = 0)
591 {
592 if ($this->status < 0) {
593 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
594 return -2;
595 }
596
597 return $this->deleteLineCommon($user, $idline, $notrigger);
598 }
599
610 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
611 {
612 global $conf, $langs;
613
614 if (!empty($conf->dol_no_mouse_hover)) {
615 $notooltip = 1; // Force disable tooltips
616 }
617
618 $result = '';
619
620 $label = '<u>'.$langs->trans("Inventory").'</u>';
621 $label .= '<br>';
622 $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
623
624 $url = dol_buildpath('/product/inventory/card.php', 1).'?id='.$this->id;
625
626 $linkclose = '';
627 if (empty($notooltip)) {
628 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
629 $label = $langs->trans("ShowInventory");
630 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
631 }
632 $linkclose .= ' title="'.dolPrintHTMLForAttribute($label).'"';
633 $linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
634 } else {
635 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
636 }
637
638 $linkstart = '<a href="'.$url.'"';
639 $linkstart .= $linkclose.'>';
640 $linkend = '</a>';
641
642 $result .= $linkstart;
643 if ($withpicto) {
644 $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);
645 }
646 if ($withpicto != 2) {
647 $result .= $this->ref;
648 }
649 $result .= $linkend;
650 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
651
652 global $action, $hookmanager;
653 $hookmanager->initHooks(array($this->element . 'dao'));
654 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
655 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
656 if ($reshook > 0) {
657 $result = $hookmanager->resPrint;
658 } else {
659 $result .= $hookmanager->resPrint;
660 }
661
662 return $result;
663 }
664
671 public function getLibStatut($mode = 0)
672 {
673 return $this->LibStatut($this->status, $mode);
674 }
675
676 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
684 public function LibStatut($status, $mode = 0)
685 {
686 // phpcs:enable
687 global $langs, $hookmanager;
688
689 $labelStatus = array();
690 $labelStatusShort = array();
691 $labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
692 $labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated').' ('.$langs->transnoentitiesnoconv('InventoryStartedShort').')';
693 $labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
694 $labelStatus[self::STATUS_RECORDED] = $langs->transnoentitiesnoconv('Closed');
695 $labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
696 $labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('InventoryStartedShort');
697 $labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Canceled');
698 $labelStatusShort[self::STATUS_RECORDED] = $langs->transnoentitiesnoconv('Closed');
699
700 $statusType = 'status'.$status;
701 if ($status == self::STATUS_RECORDED) {
702 $statusType = 'status6';
703 }
704
705 $parameters = array('status' => $status, 'mode' => $mode);
706 $reshook = $hookmanager->executeHooks('LibStatut', $parameters, $this); // Note that $action and $object may have been modified by hook
707 if ($reshook > 0) {
708 return $hookmanager->resPrint;
709 }
710 return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', $statusType, $mode);
711 }
712
720 public function getKanbanView($option = '', $arraydata = null)
721 {
722 global $conf, $langs;
723
724 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
725
726 $return = '<div class="box-flex-item box-flex-grow-zero">';
727 $return .= '<div class="info-box info-box-sm">';
728 $return .= '<span class="info-box-icon bg-infobox-action">';
729 $return .= img_picto('', $this->picto);
730 $return .= '</span>';
731 $return .= '<div class="info-box-content">';
732 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
733 if ($selected >= 0) {
734 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
735 }
736 if (property_exists($this, 'label')) {
737 $return .= ' <div class="inline-block opacitymedium valignmiddle tdoverflowmax100">'.$this->label.'</div>';
738 }
739 if (property_exists($this, 'amount')) {
740 $return .= '<br>';
741 $return .= '<span class="info-box-label amount">'.price($this->amount, 0, $langs, 1, -1, -1, $conf->currency).'</span>';
742 }
743 if (method_exists($this, 'getLibStatut')) {
744 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
745 }
746 $return .= '</div>';
747 $return .= '</div>';
748 $return .= '</div>';
749
750 return $return;
751 }
752
759 public function info($id)
760 {
761 $sql = "SELECT rowid, date_creation as datec, tms as datem, date_validation as datev,";
762 $sql .= " fk_user_creat, fk_user_modif, fk_user_valid";
763 $sql .= " FROM ".$this->db->prefix().$this->table_element." as t";
764 $sql .= " WHERE t.rowid = ".((int) $id);
765 $result = $this->db->query($sql);
766 if ($result) {
767 if ($this->db->num_rows($result)) {
768 $obj = $this->db->fetch_object($result);
769
770 $this->id = $obj->rowid;
771
772 $this->user_creation_id = $obj->fk_user_creat;
773 $this->user_modification_id = $obj->fk_user_modif;
774 $this->user_validation_id = $obj->fk_user_valid;
775
776 $this->date_creation = $this->db->jdate($obj->datec);
777 $this->date_modification = $this->db->jdate($obj->datem);
778 $this->date_validation = $this->db->jdate($obj->datev);
779 }
780
781 $this->db->free($result);
782 } else {
783 dol_print_error($this->db);
784 }
785 }
786
793 public function initAsSpecimen()
794 {
795 $ret = $this->initAsSpecimenCommon();
796 $this->title = '';
797
798 return $ret;
799 }
800
808 public function getChildWarehouse($id, &$TChildWarehouse)
809 {
810 $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'entrepot';
811 $sql .= ' WHERE fk_parent='.(int) $id;
812 $sql .= ' ORDER BY rowid';
813 $resql = $this->db->query($sql);
814 if ($resql && $this->db->num_rows($resql) > 0) {
815 while ($obj = $this->db->fetch_object($resql)) {
816 $TChildWarehouse[] = $obj->rowid;
817 $this->getChildWarehouse($obj->rowid, $TChildWarehouse);
818 }
819 return 1;
820 } else {
821 return -1;
822 }
823 }
824
825
832 public function getNextNumRef()
833 {
834 global $langs, $conf;
835 $langs->load("stocks");
836
837 if (!getDolGlobalString('INVENTORY_ADDON')) {
838 return ''; // Free reference, typed by the user (historical behaviour)
839 }
840
841 $mybool = false;
842
843 $file = getDolGlobalString('INVENTORY_ADDON').".php";
844 $classname = getDolGlobalString('INVENTORY_ADDON');
845
846 // Include file with class
847 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
848 foreach ($dirmodels as $reldir) {
849 $dir = dol_buildpath($reldir."core/modules/inventory/");
850
851 // Load file with numbering class (if found)
852 $mybool = ((bool) @include_once $dir.$file) || $mybool;
853 }
854
855 if (!$mybool) {
856 dol_print_error(null, "Failed to include file ".$file);
857 return '';
858 }
859
860 if (class_exists($classname)) {
861 $obj = new $classname();
862 '@phan-var-force ModeleNumRefInventory $obj';
863 $numref = $obj->getNextValue($this);
864
865 if ($numref != '' && $numref != '-1') {
866 return $numref;
867 } else {
868 $this->error = $obj->error;
869 return '';
870 }
871 }
872
873 return '';
874 }
875
887 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
888 {
889 global $langs;
890
891 $langs->load("stocks");
892
893 if (!dol_strlen($modele)) {
894 $modele = ''; // Remove this once a pdf_standard.php exists.
895
896 if ($this->model_pdf) {
897 $modele = $this->model_pdf;
898 } elseif (getDolGlobalString('INVENTORY_ADDON_PDF')) {
899 $modele = getDolGlobalString('INVENTORY_ADDON_PDF');
900 }
901 }
902
903 $modelpath = "core/modules/inventory/doc/";
904
905 if (empty($modele)) {
906 return 1; // Remove this once a pdf_standard.php exists.
907 }
908
909 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
910 }
911}
912
917{
921 public $element = 'inventoryline';
922
926 public $table_element = 'inventorydet';
927
931 public $parent_element = 'inventory';
932
936 public $fk_parent_attribute = 'fk_inventory';
937
941 public $picto = 'stock';
942
960 // BEGIN MODULEBUILDER PROPERTIES
964 public $fields = array(
965 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'visible' => -1, 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'index' => 1, 'comment' => 'Id',),
966 'fk_inventory' => array('type' => 'integer:Inventory:product/inventory/class/inventory.class.php', 'label' => 'Inventory', 'visible' => 1, 'enabled' => 1, 'position' => 30, 'index' => 1, 'help' => 'LinkToInventory'),
967 'fk_warehouse' => array('type' => 'integer:Entrepot:product/stock/class/entrepot.class.php', 'label' => 'Warehouse', 'visible' => 1, 'enabled' => 1, 'position' => 30, 'index' => 1, 'help' => 'LinkToThirdparty'),
968 'fk_product' => array('type' => 'integer:Product:product/class/product.class.php', 'label' => 'Product', 'visible' => 1, 'enabled' => 1, 'position' => 32, 'index' => 1, 'help' => 'LinkToProduct'),
969 'batch' => array('type' => 'string', 'label' => 'Batch', 'visible' => 1, 'enabled' => 1, 'position' => 32, 'index' => 1, 'help' => 'LinkToProduct'),
970 'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 500),
971 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 501),
972 '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)'),
973 'qty_view' => array('type' => 'double', 'label' => 'QtyBefore', 'visible' => 1, 'enabled' => 1, 'position' => 33, 'index' => 1, 'help' => 'Qty before (filled once movements are validated)'),
974 'qty_regulated' => array('type' => 'double', 'label' => 'QtyDelta', 'visible' => 1, 'enabled' => 1, 'position' => 34, 'index' => 1, 'help' => 'Qty added or removed (filled once movements are validated)'),
975 'pmp_real' => array('type' => 'double', 'label' => 'PMPReal', 'visible' => 1, 'enabled' => 1, 'position' => 35),
976 'pmp_expected' => array('type' => 'double', 'label' => 'PMPExpected', 'visible' => 1, 'enabled' => 1, 'position' => 36),
977 );
978
982 public $rowid;
983
987 public $fk_inventory;
991 public $fk_warehouse;
995 public $fk_product;
999 public $batch;
1003 public $datec;
1004
1008 public $qty_stock;
1009
1013 public $qty_view;
1014
1018 public $qty_regulated;
1019
1023 public $pmp_real;
1027 public $pmp_expected;
1028
1034 public function __construct($db)
1035 {
1036 $this->db = $db;
1037 $this->ismultientitymanaged = 0;
1038
1039 $this->isextrafieldmanaged = 0;
1040 }
1048 public function create(User $user, $notrigger = 0)
1049 {
1050 return $this->createCommon($user, $notrigger);
1051 }
1052
1060 public function fetch($id, $ref = null)
1061 {
1062 $result = $this->fetchCommon($id, $ref);
1063 //if ($result > 0 && !empty($this->table_element_line)) $this->fetchLines();
1064 return $result;
1065 }
1066
1074 public function update(User $user, $notrigger = 0)
1075 {
1076 return $this->updateCommon($user, $notrigger);
1077 }
1078
1086 public function delete(User $user, $notrigger = 0)
1087 {
1088 return $this->deleteCommon($user, $notrigger);
1089 //return $this->deleteCommon($user, $notrigger, 1);
1090 }
1091}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
deleteLineCommon(User $user, $idline, $notrigger=0)
Delete a line of object in database.
setStatut($status, $elementId=null, $elementType='', $trigkey='', $fieldstatus='')
Set status of an object.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
setErrorsFromObject($object)
setErrorsFromObject
createCommon(User $user, $notrigger=0)
Create object in the database.
updateCommon(User $user, $notrigger=0)
Update object into database.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in database.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage Dolibarr database access.
Class for Inventory.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
create(User $user, $notrigger=0)
Create object into database.
setRecorded(User $user, $notrigger=0)
Set to inventory to status "Closed".
LibStatut($status, $mode=0)
Return the status.
getKanbanView($option='', $arraydata=null)
Return a thumb for kanban views.
__construct(DoliDB $db)
Constructor.
getLibStatut($mode=0)
Return the label of the status.
info($id)
Charge les information d'ordre info dans l'objet commande.
setDraft(User $user, $notrigger=0)
Go back to draft.
update(User $user, $notrigger=0)
Load object lines in memory from the database.
setCanceled(User $user, $notrigger=0)
Set to Canceled.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
deleteLine(User $user, $idline, $notrigger=0)
Delete a line of object in database.
const START_MODE_CURRENT
How the lines of the inventory are initialized when it is started.
fetch($id, $ref=null)
Load object in memory from the database.
validate(User $user, $notrigger=0, $include_sub_warehouse=0, $startmode='')
Validate inventory (start it)
getChildWarehouse($id, &$TChildWarehouse)
Return the child warehouse of the current one.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
createFromClone(User $user, $fromid)
Clone and object into another one.
Class InventoryLine.
update(User $user, $notrigger=0)
Update object into database.
__construct($db)
Constructor.
create(User $user, $notrigger=0)
Create object in database.
fetch($id, $ref=null)
Load object in memory from the database.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:169
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_now($mode='gmt')
Return date for now.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as p p num_paiement as f pf amount as amount
Definition receipt.php:494