1<?php 2/* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org> 3 * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net> 4 * Copyright (C) 2005-2008 Regis Houssin <regis.houssin@inodbox.com> 5 * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es> 6 * Copyright (C) 2016 Francis Appels <francis.appels@yahoo.com> 7 * Copyright (C) 2019-2020 Frédéric France <frederic.france@netlogic.fr> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 3 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program. If not, see <https://www.gnu.org/licenses/>. 21 */ 22 23/** 24 * \file htdocs/product/stock/class/entrepot.class.php 25 * \ingroup stock 26 * \brief Fichier de la classe de gestion des entrepots 27 */ 28 29require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; 30 31 32/** 33 * Class to manage warehouses 34 */ 35class Entrepot extends CommonObject 36{ 37 /** 38 * @var string ID to identify managed object 39 */ 40 public $element = 'stock'; 41 42 /** 43 * @var string Name of table without prefix where object is stored 44 */ 45 public $table_element = 'entrepot'; 46 47 /** 48 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png 49 */ 50 public $picto = 'stock'; 51 52 /** 53 * @var int 0=No test on entity, 1=Test with field entity, 2=Test with link by societe 54 */ 55 public $ismultientitymanaged = 1; 56 57 /** 58 * @var string Label 59 * @deprecated 60 * @see $label 61 */ 62 public $libelle; 63 64 /** 65 * @var string Label 66 */ 67 public $label; 68 69 /** 70 * @var string description 71 */ 72 public $description; 73 74 public $statut; 75 76 /** 77 * @var string Place 78 */ 79 public $lieu; 80 81 /** 82 * @var string Address 83 */ 84 public $address; 85 86 /** 87 * @var string Zipcode 88 */ 89 public $zip; 90 91 /** 92 * @var string Town 93 */ 94 public $town; 95 96 /** 97 * @var string Phone 98 */ 99 public $phone; 100 101 /** 102 * @var string Fax 103 */ 104 public $fax; 105 106 /** 107 * @var int ID of parent 108 */ 109 public $fk_parent; 110 111 /** 112 * @var array List of short language codes for status 113 */ 114 public $statuts = array(); 115 116 /** 117 * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. 118 */ 119 public $fields = array( 120 'rowid' =>array('type'=>'integer', 'label'=>'ID', 'enabled'=>1, 'visible'=>0, 'notnull'=>1, 'position'=>10), 121 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>15), 122 'ref' =>array('type'=>'varchar(255)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'showoncombobox'=>1, 'position'=>25, 'searchall'=>1), 123 'entity' =>array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=>1, 'position'=>30), 124 'description' =>array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-2, 'position'=>35, 'searchall'=>1), 125 'lieu' =>array('type'=>'varchar(64)', 'label'=>'LocationSummary', 'enabled'=>1, 'visible'=>1, 'position'=>40, 'showoncombobox'=>1, 'searchall'=>1), 126 'fk_parent' =>array('type'=>'integer:Entrepot:product/stock/class/entrepot.class.php:1:statut=1 AND entity IN (__SHARED_ENTITIES__)', 'label'=>'ParentWarehouse', 'enabled'=>1, 'visible'=>-2, 'position'=>41), 127 'address' =>array('type'=>'varchar(255)', 'label'=>'Address', 'enabled'=>1, 'visible'=>-2, 'position'=>45, 'searchall'=>1), 128 'zip' =>array('type'=>'varchar(10)', 'label'=>'Zip', 'enabled'=>1, 'visible'=>-2, 'position'=>50, 'searchall'=>1), 129 'town' =>array('type'=>'varchar(50)', 'label'=>'Town', 'enabled'=>1, 'visible'=>-2, 'position'=>55, 'searchall'=>1), 130 'fk_departement' =>array('type'=>'sellist:c_departements:label:rowid::active=1', 'label'=>'State', 'enabled'=>1, 'visible'=>0, 'position'=>60), 131 'fk_pays' =>array('type'=>'sellist:c_country:label:rowid::active=1', 'label'=>'Country', 'enabled'=>1, 'visible'=>-2, 'position'=>65), 132 'phone' =>array('type'=>'varchar(20)', 'label'=>'Phone', 'enabled'=>1, 'visible'=>-2, 'position'=>70, 'searchall'=>1), 133 'fax' =>array('type'=>'varchar(20)', 'label'=>'Fax', 'enabled'=>1, 'visible'=>-2, 'position'=>75, 'searchall'=>1), 134 //'fk_user_author' =>array('type'=>'integer', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-2, 'position'=>82), 135 'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>300), 136 'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>301), 137 //'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>1000), 138 //'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'ModelPDF', 'enabled'=>1, 'visible'=>0, 'position'=>1010), 139 'statut' =>array('type'=>'tinyint(4)', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'position'=>500), 140 ); 141 142 /** 143 * Warehouse closed, inactive 144 */ 145 const STATUS_CLOSED = 0; 146 147 /** 148 * Warehouse open and operations for customer shipping, supplier dispatch, internal stock transfers/corrections allowed. 149 */ 150 const STATUS_OPEN_ALL = 1; 151 152 /** 153 * Warehouse open and operations for stock transfers/corrections allowed (not for customer shipping and supplier dispatch). 154 */ 155 const STATUS_OPEN_INTERNAL = 2; 156 157 158 /** 159 * Constructor 160 * 161 * @param DoliDB $db Database handler 162 */ 163 public function __construct($db) 164 { 165 global $conf; 166 $this->db = $db; 167 168 $this->statuts[self::STATUS_CLOSED] = 'Closed2'; 169 if (!empty($conf->global->ENTREPOT_EXTRA_STATUS)) { 170 $this->statuts[self::STATUS_OPEN_ALL] = 'OpenAll'; 171 $this->statuts[self::STATUS_OPEN_INTERNAL] = 'OpenInternal'; 172 } else { 173 $this->statuts[self::STATUS_OPEN_ALL] = 'Opened'; 174 } 175 } 176 177 /** 178 * Creation d'un entrepot en base 179 * 180 * @param User $user Object user that create the warehouse 181 * @return int >0 if OK, =<0 if KO 182 */ 183 public function create($user) 184 { 185 global $conf; 186 187 $error = 0; 188 189 $this->label = trim(!empty($this->label) ? $this->label : $this->libelle); 190 191 // Error if label not defined 192 if ($this->label == '') { 193 $this->error = "ErrorFieldRequired"; 194 return 0; 195 } 196 197 $now = dol_now(); 198 199 $this->db->begin(); 200 201 $sql = "INSERT INTO ".MAIN_DB_PREFIX."entrepot (ref, entity, datec, fk_user_author, fk_parent)"; 202 $sql .= " VALUES ('".$this->db->escape($this->label)."', ".$conf->entity.", '".$this->db->idate($now)."', ".$user->id.", ".($this->fk_parent > 0 ? $this->fk_parent : "NULL").")"; 203 204 dol_syslog(get_class($this)."::create", LOG_DEBUG); 205 $result = $this->db->query($sql); 206 if ($result) 207 { 208 $id = $this->db->last_insert_id(MAIN_DB_PREFIX."entrepot"); 209 if ($id > 0) 210 { 211 $this->id = $id; 212 213 if (!$error) 214 { 215 $result = $this->update($id, $user); 216 if ($result <= 0) 217 { 218 $error++; 219 } 220 } 221 222 // Actions on extra fields 223 if (!$error) 224 { 225 if (!$error) 226 { 227 $result = $this->insertExtraFields(); 228 if ($result < 0) 229 { 230 $error++; 231 } 232 } 233 } 234 235 if (!$error) 236 { 237 $this->db->commit(); 238 return $id; 239 } else { 240 dol_syslog(get_class($this)."::create return -3"); 241 $this->db->rollback(); 242 return -3; 243 } 244 } else { 245 $this->error = "Failed to get insert id"; 246 dol_syslog(get_class($this)."::create return -2"); 247 return -2; 248 } 249 } else { 250 $this->error = $this->db->error(); 251 dol_syslog(get_class($this)."::create Error ".$this->db->error()); 252 $this->db->rollback(); 253 return -1; 254 } 255 } 256 257 /** 258 * Update properties of a warehouse 259 * 260 * @param int $id id of warehouse to modify 261 * @param User $user User object 262 * @return int >0 if OK, <0 if KO 263 */ 264 public function update($id, $user) 265 { 266 global $conf; 267 268 $error = 0; 269 270 if (empty($id)) $id = $this->id; 271 if (empty($this->label)) $this->label = $this->libelle; // For backward compatibility 272 273 // Check if new parent is already a child of current warehouse 274 if (!empty($this->fk_parent)) 275 { 276 $TChildWarehouses = array($id); 277 $TChildWarehouses = $this->get_children_warehouses($this->id, $TChildWarehouses); 278 if (in_array($this->fk_parent, $TChildWarehouses)) 279 { 280 $this->error = 'ErrorCannotAddThisParentWarehouse'; 281 return -2; 282 } 283 } 284 285 $this->label = trim(!empty($this->label) ? $this->label : $this->libelle); 286 287 $this->description = trim($this->description); 288 289 $this->lieu = trim($this->lieu); 290 291 $this->address = trim($this->address); 292 $this->zip = trim($this->zip); 293 $this->town = trim($this->town); 294 $this->country_id = ($this->country_id > 0 ? $this->country_id : 0); 295 296 $sql = "UPDATE ".MAIN_DB_PREFIX."entrepot "; 297 $sql .= " SET ref = '".$this->db->escape($this->label)."'"; 298 $sql .= ", fk_parent = ".(($this->fk_parent > 0) ? $this->fk_parent : "NULL"); 299 $sql .= ", description = '".$this->db->escape($this->description)."'"; 300 $sql .= ", statut = ".$this->statut; 301 $sql .= ", lieu = '".$this->db->escape($this->lieu)."'"; 302 $sql .= ", address = '".$this->db->escape($this->address)."'"; 303 $sql .= ", zip = '".$this->db->escape($this->zip)."'"; 304 $sql .= ", town = '".$this->db->escape($this->town)."'"; 305 $sql .= ", fk_pays = ".$this->country_id; 306 $sql .= ", phone = '".$this->db->escape($this->phone)."'"; 307 $sql .= ", fax = '".$this->db->escape($this->fax)."'"; 308 $sql .= " WHERE rowid = ".$id; 309 310 $this->db->begin(); 311 312 dol_syslog(get_class($this)."::update", LOG_DEBUG); 313 $resql = $this->db->query($sql); 314 315 if (!$resql) { 316 $error++; 317 $this->errors[] = "Error ".$this->db->lasterror(); 318 } 319 320 if (!$error) { 321 $result = $this->insertExtraFields(); 322 if ($result < 0) 323 { 324 $error++; 325 } 326 } 327 328 if (!$error) { 329 $this->db->commit(); 330 return 1; 331 } else { 332 $this->db->rollback(); 333 $this->error = $this->db->lasterror(); 334 return -1; 335 } 336 } 337 338 339 /** 340 * Delete a warehouse 341 * 342 * @param User $user Object user that made deletion 343 * @param int $notrigger 1=No trigger 344 * @return int <0 if KO, >0 if OK 345 */ 346 public function delete($user, $notrigger = 0) 347 { 348 global $conf; 349 350 $error = 0; 351 352 dol_syslog(get_class($this)."::delete id=".$this->id, LOG_DEBUG); 353 354 $this->db->begin(); 355 356 if (!$error && empty($notrigger)) 357 { 358 // Call trigger 359 $result = $this->call_trigger('WAREHOUSE_DELETE', $user); 360 if ($result < 0) { $error++; } 361 // End call triggers 362 } 363 364 $elements = array('stock_mouvement', 'product_stock', 'product_warehouse_properties'); 365 foreach ($elements as $table) 366 { 367 if (!$error) 368 { 369 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$table; 370 $sql .= " WHERE fk_entrepot = ".$this->id; 371 372 $result = $this->db->query($sql); 373 if (!$result) 374 { 375 $error++; 376 $this->errors[] = $this->db->lasterror(); 377 } 378 } 379 } 380 381 // Removed extrafields 382 if (!$error) 383 { 384 if (!$error) 385 { 386 $result = $this->deleteExtraFields(); 387 if ($result < 0) 388 { 389 $error++; 390 dol_syslog(get_class($this)."::delete Error ".$this->error, LOG_ERR); 391 } 392 } 393 } 394 395 if (!$error) 396 { 397 $sql = "DELETE FROM ".MAIN_DB_PREFIX."entrepot"; 398 $sql .= " WHERE rowid = ".$this->id; 399 $resql1 = $this->db->query($sql); 400 if (!$resql1) 401 { 402 $error++; 403 $this->errors[] = $this->db->lasterror(); 404 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR); 405 } 406 } 407 408 if (!$error) 409 { 410 // Update denormalized fields because we change content of produt_stock. Warning: Do not use "SET p.stock", does not works with pgsql 411 $sql = "UPDATE ".MAIN_DB_PREFIX."product as p SET stock = (SELECT SUM(ps.reel) FROM ".MAIN_DB_PREFIX."product_stock as ps WHERE ps.fk_product = p.rowid)"; 412 $resql2 = $this->db->query($sql); 413 if (!$resql2) 414 { 415 $error++; 416 $this->errors[] = $this->db->lasterror(); 417 dol_syslog(get_class($this)."::delete Error ".$this->db->lasterror(), LOG_ERR); 418 } 419 } 420 421 if (!$error) 422 { 423 $this->db->commit(); 424 return 1; 425 } else { 426 $this->db->rollback(); 427 return -1; 428 } 429 } 430 431 432 /** 433 * Load warehouse data 434 * 435 * @param int $id Warehouse id 436 * @param string $ref Warehouse label 437 * @return int >0 if OK, <0 if KO 438 */ 439 public function fetch($id, $ref = '') 440 { 441 global $conf; 442 443 dol_syslog(get_class($this)."::fetch id=".$id." ref=".$ref); 444 445 // Check parameters 446 if (!$id && !$ref) 447 { 448 $this->error = 'ErrorWrongParameters'; 449 dol_syslog(get_class($this)."::fetch ".$this->error); 450 return -1; 451 } 452 453 $sql = "SELECT rowid, entity, fk_parent, ref as label, description, statut, lieu, address, zip, town, fk_pays as country_id, phone, fax,"; 454 $sql .= " model_pdf, import_key"; 455 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot"; 456 if ($id) 457 { 458 $sql .= " WHERE rowid = '".$id."'"; 459 } else { 460 $sql .= " WHERE entity = ".$conf->entity; 461 if ($ref) $sql .= " AND ref = '".$this->db->escape($ref)."'"; 462 } 463 464 $result = $this->db->query($sql); 465 if ($result) 466 { 467 if ($this->db->num_rows($result) > 0) 468 { 469 $obj = $this->db->fetch_object($result); 470 471 $this->id = $obj->rowid; 472 $this->entity = $obj->entity; 473 $this->fk_parent = $obj->fk_parent; 474 $this->ref = $obj->label; 475 $this->label = $obj->label; 476 $this->libelle = $obj->label; // deprecated 477 $this->description = $obj->description; 478 $this->statut = $obj->statut; 479 $this->lieu = $obj->lieu; 480 $this->address = $obj->address; 481 $this->zip = $obj->zip; 482 $this->town = $obj->town; 483 $this->country_id = $obj->country_id; 484 $this->phone = $obj->phone; 485 $this->fax = $obj->fax; 486 487 $this->model_pdf = $obj->model_pdf; 488 $this->import_key = $obj->import_key; 489 490 // Retrieve all extrafield 491 // fetch optionals attributes and labels 492 $this->fetch_optionals(); 493 494 include_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; 495 $tmp = getCountry($this->country_id, 'all'); 496 $this->country = $tmp['label']; 497 $this->country_code = $tmp['code']; 498 499 return 1; 500 } else { 501 $this->error = "Record Not Found"; 502 return 0; 503 } 504 } else { 505 $this->error = $this->db->error(); 506 return -1; 507 } 508 } 509 510 511 /** 512 * Load warehouse info data 513 * 514 * @param int $id warehouse id 515 * @return void 516 */ 517 public function info($id) 518 { 519 $sql = "SELECT e.rowid, e.datec, e.tms as datem, e.fk_user_author"; 520 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e"; 521 $sql .= " WHERE e.rowid = ".$id; 522 523 dol_syslog(get_class($this)."::info", LOG_DEBUG); 524 $result = $this->db->query($sql); 525 if ($result) 526 { 527 if ($this->db->num_rows($result)) 528 { 529 $obj = $this->db->fetch_object($result); 530 531 $this->id = $obj->rowid; 532 533 if ($obj->fk_user_author) { 534 $cuser = new User($this->db); 535 $cuser->fetch($obj->fk_user_author); 536 $this->user_creation = $cuser; 537 } 538 539 if ($obj->fk_user_valid) { 540 $vuser = new User($this->db); 541 $vuser->fetch($obj->fk_user_valid); 542 $this->user_validation = $vuser; 543 } 544 545 $this->date_creation = $this->db->jdate($obj->datec); 546 $this->date_modification = $this->db->jdate($obj->datem); 547 } 548 549 $this->db->free($result); 550 } else { 551 dol_print_error($this->db); 552 } 553 } 554 555 556 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 557 /** 558 * Return list of all warehouses 559 * 560 * @param int $status Status 561 * @return array Array list of warehouses 562 */ 563 public function list_array($status = 1) 564 { 565 // phpcs:enable 566 $liste = array(); 567 568 $sql = "SELECT rowid, ref as label"; 569 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot"; 570 $sql .= " WHERE entity IN (".getEntity('stock').")"; 571 $sql .= " AND statut = ".$status; 572 573 $result = $this->db->query($sql); 574 $i = 0; 575 $num = $this->db->num_rows($result); 576 if ($result) 577 { 578 while ($i < $num) 579 { 580 $row = $this->db->fetch_row($result); 581 $liste[$row[0]] = $row[1]; 582 $i++; 583 } 584 $this->db->free($result); 585 } 586 return $liste; 587 } 588 589 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 590 /** 591 * Return number of unique different product into a warehouse 592 * 593 * @return Array Array('nb'=>Nb, 'value'=>Value) 594 */ 595 public function nb_different_products() 596 { 597 // phpcs:enable 598 $ret = array(); 599 600 $sql = "SELECT count(distinct p.rowid) as nb"; 601 $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps"; 602 $sql .= ", ".MAIN_DB_PREFIX."product as p"; 603 $sql .= " WHERE ps.fk_entrepot = ".$this->id; 604 $sql .= " AND ps.fk_product = p.rowid"; 605 606 //print $sql; 607 $result = $this->db->query($sql); 608 if ($result) 609 { 610 $obj = $this->db->fetch_object($result); 611 $ret['nb'] = $obj->nb; 612 $this->db->free($result); 613 } else { 614 $this->error = $this->db->lasterror(); 615 return -1; 616 } 617 618 return $ret; 619 } 620 621 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 622 /** 623 * Return stock and value of warehosue 624 * 625 * @return Array Array('nb'=>Nb, 'value'=>Value) 626 */ 627 public function nb_products() 628 { 629 // phpcs:enable 630 $ret = array(); 631 632 $sql = "SELECT sum(ps.reel) as nb, sum(ps.reel * p.pmp) as value"; 633 $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps"; 634 $sql .= ", ".MAIN_DB_PREFIX."product as p"; 635 $sql .= " WHERE ps.fk_entrepot = ".$this->id; 636 $sql .= " AND ps.fk_product = p.rowid"; 637 638 //print $sql; 639 $result = $this->db->query($sql); 640 if ($result) 641 { 642 $obj = $this->db->fetch_object($result); 643 $ret['nb'] = $obj->nb; 644 $ret['value'] = $obj->value; 645 $this->db->free($result); 646 } else { 647 $this->error = $this->db->lasterror(); 648 return -1; 649 } 650 651 return $ret; 652 } 653 654 /** 655 * Return label of status of object 656 * 657 * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto 658 * @return string Label of status 659 */ 660 public function getLibStatut($mode = 0) 661 { 662 return $this->LibStatut($this->statut, $mode); 663 } 664 665 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 666 /** 667 * Return label of a given status 668 * 669 * @param int $status Id status 670 * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto 671 * @return string Label of status 672 */ 673 public function LibStatut($status, $mode = 0) 674 { 675 // phpcs:enable 676 global $langs; 677 678 $statusType = 'status5'; 679 if ($status > 0) $statusType = 'status4'; 680 681 $langs->load('stocks'); 682 $label = $langs->trans($this->statuts[$status]); 683 $labelshort = $langs->trans($this->statuts[$status]); 684 685 return dolGetStatus($label, $labelshort, '', $statusType, $mode); 686 } 687 688 689 /** 690 * Return clickable name (possibility with the pictogram) 691 * 692 * @param int $withpicto with pictogram 693 * @param string $option Where the link point to 694 * @param int $showfullpath 0=Show ref only. 1=Show full path instead of Ref (this->fk_parent must be defined) 695 * @param int $notooltip 1=Disable tooltip 696 * @return string String with URL 697 */ 698 public function getNomUrl($withpicto = 0, $option = '', $showfullpath = 0, $notooltip = 0) 699 { 700 global $conf, $langs, $hookmanager; 701 $langs->load("stocks"); 702 703 if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips 704 705 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpicto) $withpicto = 0; 706 707 $result = ''; 708 709 $label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Warehouse").'</u>'; 710 if (isset($this->statut)) { 711 $label .= ' '.$this->getLibStatut(5); 712 } 713 $label .= '<br><b>'.$langs->trans('Ref').':</b> '.(empty($this->ref) ? (empty($this->label) ? $this->libelle : $this->label) : $this->ref); 714 if (!empty($this->lieu)) { 715 $label .= '<br><b>'.$langs->trans('LocationSummary').':</b> '.$this->lieu; 716 } 717 718 $url = DOL_URL_ROOT.'/product/stock/card.php?id='.$this->id; 719 720 $linkclose = ''; 721 if (empty($notooltip)) 722 { 723 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) 724 { 725 $label = $langs->trans("Warehouse"); 726 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; 727 } 728 $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; 729 $linkclose .= ' class="classfortooltip"'; 730 } 731 732 $linkstart = '<a href="'.$url.'"'; 733 $linkstart .= $linkclose.'>'; 734 $linkend = '</a>'; 735 736 $result .= $linkstart; 737 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); 738 if ($withpicto != 2) $result .= (($showfullpath || !empty($conf->global->STOCK_ALWAYS_SHOW_FULL_ARBO)) ? $this->get_full_arbo() : (empty($this->label) ? $this->libelle : $this->label)); 739 $result .= $linkend; 740 741 global $action; 742 $hookmanager->initHooks(array('warehousedao')); 743 $parameters = array('id'=>$this->id, 'getnomurl'=>$result, 'withpicto' => $withpicto, 'option' => $option, 'showfullpath' => $showfullpath, 'notooltip'=> $notooltip); 744 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks 745 if ($reshook > 0) { 746 $result = $hookmanager->resPrint; 747 } else { 748 $result .= $hookmanager->resPrint; 749 } 750 751 return $result; 752 } 753 754 /** 755 * Initialise an instance with random values. 756 * Used to build previews or test instances. 757 * id must be 0 if object instance is a specimen. 758 * 759 * @return void 760 */ 761 public function initAsSpecimen() 762 { 763 global $user, $langs, $conf, $mysoc; 764 765 $now = dol_now(); 766 767 // Initialize parameters 768 $this->id = 0; 769 $this->label = 'WAREHOUSE SPECIMEN'; 770 $this->description = 'WAREHOUSE SPECIMEN '.dol_print_date($now, 'dayhourlog'); 771 $this->statut = 1; 772 $this->specimen = 1; 773 774 $this->lieu = 'Location test'; 775 $this->address = '21 jump street'; 776 $this->zip = '99999'; 777 $this->town = 'MyTown'; 778 $this->country_id = 1; 779 $this->country_code = 'FR'; 780 } 781 782 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 783 /** 784 * Return full path to current warehouse 785 * 786 * @return string String full path to current warehouse separated by " >> " 787 */ 788 public function get_full_arbo() 789 { 790 // phpcs:enable 791 global $user, $langs, $conf; 792 793 $TArbo = array(empty($this->label) ? $this->libelle : $this->label); 794 795 $protection = 100; // We limit depth of warehouses to 100 796 797 $warehousetmp = new Entrepot($this->db); 798 799 $parentid = $this->fk_parent; // If parent_id not defined on current object, we do not start consecutive searches of parents 800 $i = 0; 801 while ($parentid > 0 && $i < $protection) 802 { 803 $sql = 'SELECT fk_parent FROM '.MAIN_DB_PREFIX.'entrepot WHERE rowid = '.$parentid; 804 $resql = $this->db->query($sql); 805 if ($resql) 806 { 807 $objarbo = $this->db->fetch_object($resql); 808 if ($objarbo) 809 { 810 $warehousetmp->fetch($parentid); 811 $TArbo[] = $warehousetmp->label; 812 $parentid = $objarbo->fk_parent; 813 } else break; 814 } else dol_print_error($this->db); 815 816 $i++; 817 } 818 819 return implode(' >> ', array_reverse($TArbo)); 820 } 821 822 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 823 /** 824 * Return array of children warehouses ids from $id warehouse (recursive function) 825 * 826 * @param int $id id parent warehouse 827 * @param integer[] $TChildWarehouses array which will contain all children (param by reference) 828 * @return integer[] $TChildWarehouses array which will contain all children 829 */ 830 public function get_children_warehouses($id, &$TChildWarehouses) 831 { 832 // phpcs:enable 833 834 $sql = 'SELECT rowid 835 FROM '.MAIN_DB_PREFIX.'entrepot 836 WHERE fk_parent = '.$id; 837 838 $resql = $this->db->query($sql); 839 if ($resql) { 840 while ($res = $this->db->fetch_object($resql)) { 841 $TChildWarehouses[] = $res->rowid; 842 $this->get_children_warehouses($res->rowid, $TChildWarehouses); 843 } 844 } 845 846 return $TChildWarehouses; 847 } 848 849 /** 850 * Create object on disk 851 * 852 * @param string $modele force le modele a utiliser ('' to not force) 853 * @param Translate $outputlangs Object langs to use for output 854 * @param int $hidedetails Hide details of lines 855 * @param int $hidedesc Hide description 856 * @param int $hideref Hide ref 857 * @return int 0 if KO, 1 if OK 858 */ 859 public function generateDocument($modele, $outputlangs = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0) 860 { 861 global $conf, $user, $langs; 862 863 $langs->load("stocks"); 864 $outputlangs->load("products"); 865 866 if (!dol_strlen($modele)) { 867 $modele = 'standard'; 868 869 if ($this->model_pdf) { 870 $modele = $this->model_pdf; 871 } elseif (!empty($conf->global->STOCK_ADDON_PDF)) { 872 $modele = $conf->global->STOCK_ADDON_PDF; 873 } 874 } 875 876 $modelpath = "core/modules/stock/doc/"; 877 878 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); 879 } 880 881 /** 882 * Sets object to supplied categories. 883 * 884 * Deletes object from existing categories not supplied. 885 * Adds it to non existing supplied categories. 886 * Existing categories are left untouch. 887 * 888 * @param int[]|int $categories Category or categories IDs 889 * @return void 890 */ 891 public function setCategories($categories) 892 { 893 $type_categ = Categorie::TYPE_WAREHOUSE; 894 895 // Handle single category 896 if (!is_array($categories)) { 897 $categories = array($categories); 898 } 899 900 // Get current categories 901 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; 902 $c = new Categorie($this->db); 903 $existing = $c->containing($this->id, $type_categ, 'id'); 904 905 // Diff 906 if (is_array($existing)) { 907 $to_del = array_diff($existing, $categories); 908 $to_add = array_diff($categories, $existing); 909 } else { 910 $to_del = array(); // Nothing to delete 911 $to_add = $categories; 912 } 913 914 // Process 915 foreach ($to_del as $del) { 916 if ($c->fetch($del) > 0) { 917 $c->del_type($this, $type_categ); 918 } 919 } 920 foreach ($to_add as $add) { 921 if ($c->fetch($add) > 0) { 922 $c->add_type($this, $type_categ); 923 } 924 } 925 926 return; 927 } 928} 929