123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- <?php
- /* Copyright (C) 2008-2009 Laurent Destailleur <eldy@users.sourceforge.net>
- * Copyright (C) 2015-2017 Francis Appels <francis.appels@yahoo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- /**
- * \file htdocs/product/class/html.formproduct.class.php
- * \brief Fichier de la classe des fonctions predefinie de composants html
- */
- require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
- /**
- * Class with static methods for building HTML components related to products
- * Only components common to products and services must be here.
- */
- class FormProduct
- {
- /**
- * @var DoliDB Database handler.
- */
- public $db;
- /**
- * @var string Error code (or message)
- */
- public $error = '';
- // Cache arrays
- public $cache_warehouses = array();
- public $cache_lot = array();
- /**
- * Constructor
- *
- * @param DoliDB $db Database handler
- */
- public function __construct($db)
- {
- $this->db = $db;
- }
- /**
- * Load in cache array list of warehouses
- * If fk_product is not 0, we do not use cache
- *
- * @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
- * @param string $batch Add quantity of batch stock in label for product with batch name batch, batch name precedes batch_id. Nothing if ''.
- * @param string $status warehouse status filter, following comma separated filter options can be used
- * 'warehouseopen' = select products from open warehouses,
- * 'warehouseclosed' = select products from closed warehouses,
- * 'warehouseinternal' = select products from warehouses for internal correct/transfer only
- * @param boolean $sumStock sum total stock of a warehouse, default true
- * @param array $exclude warehouses ids to exclude
- * @param bool|int $stockMin [=false] Value of minimum stock to filter or false not not filter by minimum stock
- * @param string $orderBy [='e.ref'] Order by
- * @return int Nb of loaded lines, 0 if already loaded, <0 if KO
- * @throws Exception
- */
- public function loadWarehouses($fk_product = 0, $batch = '', $status = '', $sumStock = true, $exclude = array(), $stockMin = false, $orderBy = 'e.ref')
- {
- global $conf, $langs;
- if (empty($fk_product) && count($this->cache_warehouses)) {
- return 0; // Cache already loaded and we do not want a list with information specific to a product
- }
- $warehouseStatus = array();
- if (preg_match('/warehouseclosed/', $status)) {
- $warehouseStatus[] = Entrepot::STATUS_CLOSED;
- }
- if (preg_match('/warehouseopen/', $status)) {
- $warehouseStatus[] = Entrepot::STATUS_OPEN_ALL;
- }
- if (preg_match('/warehouseinternal/', $status)) {
- $warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
- }
- $sql = "SELECT e.rowid, e.ref as label, e.description, e.fk_parent";
- if (!empty($fk_product) && $fk_product > 0) {
- if (!empty($batch)) {
- $sql .= ", pb.qty as stock";
- } else {
- $sql .= ", ps.reel as stock";
- }
- } elseif ($sumStock) {
- $sql .= ", sum(ps.reel) as stock";
- }
- $sql .= " FROM ".$this->db->prefix()."entrepot as e";
- $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_entrepot = e.rowid";
- if (!empty($fk_product) && $fk_product > 0) {
- $sql .= " AND ps.fk_product = ".((int) $fk_product);
- if (!empty($batch)) {
- $sql .= " LEFT JOIN ".$this->db->prefix()."product_batch as pb on pb.fk_product_stock = ps.rowid AND pb.batch = '".$this->db->escape($batch)."'";
- }
- }
- $sql .= " WHERE e.entity IN (".getEntity('stock').")";
- if (count($warehouseStatus)) {
- $sql .= " AND e.statut IN (".$this->db->sanitize(implode(',', $warehouseStatus)).")";
- } else {
- $sql .= " AND e.statut = 1";
- }
- if (is_array($exclude) && !empty($exclude)) {
- $sql .= ' AND e.rowid NOT IN('.$this->db->sanitize(implode(',', $exclude)).')';
- }
- // minimum stock
- if ($stockMin !== false) {
- if (!empty($fk_product) && $fk_product > 0) {
- if (!empty($batch)) {
- $sql .= " AND pb.qty > ".((float) $stockMin);
- } else {
- $sql .= " AND ps.reel > ".((float) $stockMin);
- }
- }
- }
- if ($sumStock && empty($fk_product)) {
- $sql .= " GROUP BY e.rowid, e.ref, e.description, e.fk_parent";
- // minimum stock
- if ($stockMin !== false) {
- $sql .= " HAVING sum(ps.reel) > ".((float) $stockMin);
- }
- }
- $sql .= " ORDER BY ".$orderBy;
- dol_syslog(get_class($this).'::loadWarehouses', LOG_DEBUG);
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- $i = 0;
- while ($i < $num) {
- $obj = $this->db->fetch_object($resql);
- if ($sumStock) {
- $obj->stock = price2num($obj->stock, 5);
- }
- $this->cache_warehouses[$obj->rowid]['id'] = $obj->rowid;
- $this->cache_warehouses[$obj->rowid]['label'] = $obj->label;
- $this->cache_warehouses[$obj->rowid]['parent_id'] = $obj->fk_parent;
- $this->cache_warehouses[$obj->rowid]['description'] = $obj->description;
- $this->cache_warehouses[$obj->rowid]['stock'] = $obj->stock;
- $i++;
- }
- // Full label init
- foreach ($this->cache_warehouses as $obj_rowid => $tab) {
- $this->cache_warehouses[$obj_rowid]['full_label'] = $this->get_parent_path($tab);
- }
- return $num;
- } else {
- dol_print_error($this->db);
- return -1;
- }
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Return full path to current warehouse in $tab (recursive function)
- *
- * @param array $tab warehouse data in $this->cache_warehouses line
- * @param String $final_label full label with all parents, separated by ' >> ' (completed on each call)
- * @return String full label with all parents, separated by ' >> '
- */
- private function get_parent_path($tab, $final_label = '')
- {
- //phpcs:enable
- if (empty($final_label)) {
- $final_label = $tab['label'];
- }
- if (empty($tab['parent_id'])) {
- return $final_label;
- } else {
- if (!empty($this->cache_warehouses[$tab['parent_id']])) {
- $final_label = $this->cache_warehouses[$tab['parent_id']]['label'].' >> '.$final_label;
- return $this->get_parent_path($this->cache_warehouses[$tab['parent_id']], $final_label);
- }
- }
- return $final_label;
- }
- /**
- * Return list of warehouses
- *
- * @param string|int $selected Id of preselected warehouse ('' or '-1' for no value, 'ifone' and 'ifonenodefault' = select value if one value otherwise no value, '-2' to use the default value from setup)
- * @param string $htmlname Name of html select html
- * @param string $filterstatus warehouse status filter, following comma separated filter options can be used
- * 'warehouseopen' = select products from open warehouses,
- * 'warehouseclosed' = select products from closed warehouses,
- * 'warehouseinternal' = select products from warehouses for internal correct/transfer only
- * @param int $empty 1=Can be empty, 0 if not
- * @param int $disabled 1=Select is disabled
- * @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
- * @param string $empty_label Empty label if needed (only if $empty=1)
- * @param int $showstock 1=Show stock count
- * @param int $forcecombo 1=Force combo iso ajax select2
- * @param array $events Events to add to select2
- * @param string $morecss Add more css classes to HTML select
- * @param array $exclude Warehouses ids to exclude
- * @param int $showfullpath 1=Show full path of name (parent ref into label), 0=Show only ref of current warehouse
- * @param bool|int $stockMin [=false] Value of minimum stock to filter or false not not filter by minimum stock
- * @param string $orderBy [='e.ref'] Order by
- * @return string HTML select
- *
- * @throws Exception
- */
- public function selectWarehouses($selected = '', $htmlname = 'idwarehouse', $filterstatus = '', $empty = 0, $disabled = 0, $fk_product = 0, $empty_label = '', $showstock = 0, $forcecombo = 0, $events = array(), $morecss = 'minwidth200', $exclude = array(), $showfullpath = 1, $stockMin = false, $orderBy = 'e.ref')
- {
- global $conf, $langs, $user, $hookmanager;
- dol_syslog(get_class($this)."::selectWarehouses $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $empty_label, $showstock, $forcecombo, $morecss", LOG_DEBUG);
- $out = '';
- if (empty($conf->global->ENTREPOT_EXTRA_STATUS)) {
- $filterstatus = '';
- }
- if (!empty($fk_product) && $fk_product > 0) {
- $this->cache_warehouses = array();
- }
- $this->loadWarehouses($fk_product, '', $filterstatus, true, $exclude, $stockMin, $orderBy);
- $nbofwarehouses = count($this->cache_warehouses);
- if ($conf->use_javascript_ajax && !$forcecombo) {
- include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
- $comboenhancement = ajax_combobox($htmlname, $events);
- $out .= $comboenhancement;
- }
- if (strpos($htmlname, 'search_') !== 0) {
- if (empty($user->fk_warehouse) || $user->fk_warehouse == -1) {
- if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) {
- $selected = $conf->global->MAIN_DEFAULT_WAREHOUSE;
- }
- } else {
- if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER)) {
- $selected = $user->fk_warehouse;
- }
- }
- }
- $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled' : '').' id="'.$htmlname.'" name="'.($htmlname.($disabled ? '_disabled' : '')).'">';
- if ($empty) {
- $out .= '<option value="-1">'.($empty_label ? $empty_label : ' ').'</option>';
- }
- foreach ($this->cache_warehouses as $id => $arraytypes) {
- $label = '';
- if ($showfullpath) {
- $label .= $arraytypes['full_label'];
- } else {
- $label .= $arraytypes['label'];
- }
- if (($fk_product || ($showstock > 0)) && ($arraytypes['stock'] != 0 || ($showstock > 0))) {
- if ($arraytypes['stock'] <= 0) {
- $label .= ' <span class= \'text-warning\'>('.$langs->trans("Stock").':'.$arraytypes['stock'].')</span>';
- } else {
- $label .= ' <span class=\'opacitymedium\'>('.$langs->trans("Stock").':'.$arraytypes['stock'].')</span>';
- }
- }
- $out .= '<option value="'.$id.'"';
- if ($selected == $id || (preg_match('/^ifone/', $selected) && $nbofwarehouses == 1)) {
- $out .= ' selected';
- }
- $out .= ' data-html="'.dol_escape_htmltag($label).'"';
- $out .= '>';
- $out .= $label;
- $out .= '</option>';
- }
- $out .= '</select>';
- if ($disabled) {
- $out .= '<input type="hidden" name="'.$htmlname.'" value="'.(($selected > 0) ? $selected : '').'">';
- }
- $parameters = array(
- 'selected' => $selected,
- 'htmlname' => $htmlname,
- 'filterstatus' => $filterstatus,
- 'empty' => $empty,
- 'disabled ' => $disabled,
- 'fk_product' => $fk_product,
- 'empty_label' => $empty_label,
- 'showstock' => $showstock,
- 'forcecombo' => $forcecombo,
- 'events' => $events,
- 'morecss' => $morecss,
- 'exclude' => $exclude,
- 'showfullpath' => $showfullpath,
- 'stockMin' => $stockMin,
- 'orderBy' => $orderBy
- );
- $reshook = $hookmanager->executeHooks('selectWarehouses', $parameters, $this);
- if ($reshook > 0) {
- $out = $hookmanager->resPrint;
- } elseif ($reshook == 0) {
- $out .= $hookmanager->resPrint;
- }
- return $out;
- }
- /**
- * Display form to select warehouse
- *
- * @param string $page Page
- * @param int $selected Id of warehouse
- * @param string $htmlname Name of select html field
- * @param int $addempty 1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
- * @return void
- */
- public function formSelectWarehouses($page, $selected = '', $htmlname = 'warehouse_id', $addempty = 0)
- {
- global $langs;
- if ($htmlname != "none") {
- print '<form method="POST" action="'.$page.'">';
- print '<input type="hidden" name="action" value="setwarehouse">';
- print '<input type="hidden" name="token" value="'.newToken().'">';
- print '<table class="nobordernopadding">';
- print '<tr><td>';
- print $this->selectWarehouses($selected, $htmlname, '', $addempty);
- print '</td>';
- print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
- print '</tr></table></form>';
- } else {
- if ($selected) {
- require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
- $warehousestatic = new Entrepot($this->db);
- $warehousestatic->fetch($selected);
- print $warehousestatic->getNomUrl();
- } else {
- print " ";
- }
- }
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Output a combo box with list of units
- * pour l'instant on ne definit pas les unites dans la base
- *
- * @param string $name Name of HTML field
- * @param string $measuring_style Unit to show: weight, size, surface, volume, time
- * @param string $default Preselected value
- * @param int $adddefault Add empty unit called "Default"
- * @param int $mode 1=Use short label as value, 0=Use rowid
- * @return void
- * @deprecated
- */
- public function select_measuring_units($name = 'measuring_units', $measuring_style = '', $default = '0', $adddefault = 0, $mode = 0)
- {
- //phpcs:enable
- print $this->selectMeasuringUnits($name, $measuring_style, $default, $adddefault, $mode);
- }
- /**
- * Return a combo box with list of units
- * Units labels are defined in llx_c_units
- *
- * @param string $name Name of HTML field
- * @param string $measuring_style Unit to show: weight, size, surface, volume, time
- * @param string $default Preselected value
- * @param int|string $adddefault 1=Add empty unit called "Default", ''=Add empty value
- * @param int $mode 1=Use short label as value, 0=Use rowid, 2=Use scale (power)
- * @param string $morecss More CSS
- * @return string
- */
- public function selectMeasuringUnits($name = 'measuring_units', $measuring_style = '', $default = '0', $adddefault = 0, $mode = 0, $morecss = 'maxwidth125')
- {
- global $langs, $conf, $mysoc, $db;
- $langs->load("other");
- $return = '';
- // TODO Use a cache
- require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
- $measuringUnits = new CUnits($db);
- $filter = array();
- $filter['t.active'] = 1;
- if ($measuring_style) {
- $filter['t.unit_type'] = $measuring_style;
- }
- $result = $measuringUnits->fetchAll(
- '',
- '',
- 0,
- 0,
- $filter
- );
- if ($result < 0) {
- dol_print_error($db);
- return -1;
- } else {
- $return .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$name.'" id="'.$name.'">';
- if ($adddefault || $adddefault === '') {
- $return .= '<option value="0">'.($adddefault ? $langs->trans("Default") : '').'</option>';
- }
- foreach ($measuringUnits->records as $lines) {
- $return .= '<option value="';
- if ($mode == 1) {
- $return .= $lines->short_label;
- } elseif ($mode == 2) {
- $return .= $lines->scale;
- } else {
- $return .= $lines->id;
- }
- $return .= '"';
- if ($mode == 1 && $lines->short_label == $default) {
- $return .= ' selected';
- } elseif ($mode == 2 && $lines->scale == $default) {
- $return .= ' selected';
- } elseif ($mode == 0 && $lines->id == $default) {
- $return .= ' selected';
- }
- $return .= '>';
- if ($measuring_style == 'time') {
- $return .= $langs->trans(ucfirst($lines->label));
- } else {
- $return .= $langs->trans($lines->label);
- }
- $return .= '</option>';
- }
- $return .= '</select>';
- }
- $return .= ajax_combobox($name);
- return $return;
- }
- /**
- * Return a combo box with list of units
- * NAture of product labels are defined in llx_c_product_nature
- *
- * @param string $name Name of HTML field
- * @param string $selected Preselected value
- * @param int $mode 1=Use label as value, 0=Use code
- * @param int $showempty 1=show empty value, 0= no
- * @return string
- */
- public function selectProductNature($name = 'finished', $selected = '', $mode = 0, $showempty = 1)
- {
- global $langs, $db;
- $langs->load('products');
- $return = '';
- // TODO Use a cache
- require_once DOL_DOCUMENT_ROOT.'/core/class/cproductnature.class.php';
- $productNature = new CProductNature($db);
- $filter = array();
- $filter['t.active'] = 1;
- $result = $productNature->fetchAll('', '', 0, 0, $filter);
- if ($result < 0) {
- dol_print_error($db);
- return -1;
- } else {
- $return .= '<select class="flat" name="'.$name.'" id="'.$name.'">';
- if ($showempty || ($selected == '' || $selected == '-1')) {
- $return .= '<option value="-1"';
- if ($selected == '' || $selected == '-1') {
- $return .= ' selected';
- }
- $return .= '></option>';
- }
- if (!empty($productNature->records) && is_array($productNature->records)) {
- foreach ($productNature->records as $lines) {
- $return .= '<option value="';
- if ($mode == 1) {
- $return .= $lines->label;
- } else {
- $return .= $lines->code;
- }
- $return .= '"';
- if ($mode == 1 && $lines->label == $selected) {
- $return .= ' selected';
- } elseif ($lines->code == $selected) {
- $return .= ' selected';
- }
- $return .= '>';
- $return .= $langs->trans($lines->label);
- $return .= '</option>';
- }
- }
- $return .= '</select>';
- }
- $return .= ajax_combobox($name);
- return $return;
- }
- /**
- * Return list of lot numbers (stock from product_batch) with stock location and stock qty
- *
- * @param int $selected Id of preselected lot stock id ('' for no value, 'ifone'=select value if one value otherwise no value)
- * @param string $htmlname Name of html select html
- * @param string $filterstatus lot status filter, following comma separated filter options can be used
- * @param int $empty 1=Can be empty, 0 if not
- * @param int $disabled 1=Select is disabled
- * @param int $fk_product show lot numbers of product with id fk_product. All from objectLines if 0.
- * @param int $fk_entrepot filter lot numbers for warehouse with id fk_entrepot. All if 0.
- * @param array $objectLines Only cache lot numbers for products in lines of object. If no lines only for fk_product. If no fk_product, all.
- * @param string $empty_label Empty label if needed (only if $empty=1)
- * @param int $forcecombo 1=Force combo iso ajax select2
- * @param array $events Events to add to select2
- * @param string $morecss Add more css classes to HTML select
- *
- * @return string HTML select
- */
- public function selectLotStock($selected = '', $htmlname = 'batch_id', $filterstatus = '', $empty = 0, $disabled = 0, $fk_product = 0, $fk_entrepot = 0, $objectLines = array(), $empty_label = '', $forcecombo = 0, $events = array(), $morecss = 'minwidth200')
- {
- global $conf, $langs;
- dol_syslog(get_class($this)."::selectLotStock $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $fk_entrepot, $empty_label, $forcecombo, $morecss", LOG_DEBUG);
- $out = '';
- $productIdArray = array();
- if (!is_array($objectLines) || !count($objectLines)) {
- if (!empty($fk_product) && $fk_product > 0) {
- $productIdArray[] = (int) $fk_product;
- }
- } else {
- foreach ($objectLines as $line) {
- if ($line->fk_product) {
- $productIdArray[] = $line->fk_product;
- }
- }
- }
- $nboflot = $this->loadLotStock($productIdArray);
- if ($conf->use_javascript_ajax && !$forcecombo) {
- include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
- $comboenhancement = ajax_combobox($htmlname, $events);
- $out .= $comboenhancement;
- }
- $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled' : '').' id="'.$htmlname.'" name="'.($htmlname.($disabled ? '_disabled' : '')).'">';
- if ($empty) {
- $out .= '<option value="-1">'.($empty_label ? $empty_label : ' ').'</option>';
- }
- if (!empty($fk_product) && $fk_product > 0) {
- $productIdArray = array((int) $fk_product); // only show lot stock for product
- } else {
- foreach ($this->cache_lot as $key => $value) {
- $productIdArray[] = $key;
- }
- }
- foreach ($productIdArray as $productId) {
- foreach ($this->cache_lot[$productId] as $id => $arraytypes) {
- if (empty($fk_entrepot) || $fk_entrepot == $arraytypes['entrepot_id']) {
- $label = $arraytypes['entrepot_label'].' - ';
- $label .= $arraytypes['batch'];
- if ($arraytypes['qty'] <= 0) {
- $label .= ' <span class=\'text-warning\'>('.$langs->trans("Stock").' '.$arraytypes['qty'].')</span>';
- } else {
- $label .= ' <span class=\'opacitymedium\'>('.$langs->trans("Stock").' '.$arraytypes['qty'].')</span>';
- }
- $out .= '<option value="'.$id.'"';
- if ($selected == $id || ($selected == 'ifone' && $nboflot == 1)) {
- $out .= ' selected';
- }
- $out .= ' data-html="'.dol_escape_htmltag($label).'"';
- $out .= '>';
- $out .= $label;
- $out .= '</option>';
- }
- }
- }
- $out .= '</select>';
- if ($disabled) {
- $out .= '<input type="hidden" name="'.$htmlname.'" value="'.(($selected > 0) ? $selected : '').'">';
- }
- return $out;
- }
- /**
- * Return list of lot numbers (stock from product_batch) for product and warehouse.
- *
- * @param string $htmlname Name of key that is inside attribute "list" of an input text field.
- * @param int $empty 1=Can be empty, 0 if not
- * @param int $fk_product show lot numbers of product with id fk_product. All from objectLines if 0.
- * @param int $fk_entrepot filter lot numbers for warehouse with id fk_entrepot. All if 0.
- * @param array $objectLines Only cache lot numbers for products in lines of object. If no lines only for fk_product. If no fk_product, all.
- * @return string HTML datalist
- */
- public function selectLotDataList($htmlname = 'batch_id', $empty = 0, $fk_product = 0, $fk_entrepot = 0, $objectLines = array())
- {
- global $conf, $langs;
- dol_syslog(get_class($this)."::selectLotDataList $htmlname, $empty, $fk_product, $fk_entrepot,$objectLines", LOG_DEBUG);
- $out = '';
- $productIdArray = array();
- if (!is_array($objectLines) || !count($objectLines)) {
- if (!empty($fk_product) && $fk_product > 0) {
- $productIdArray[] = (int) $fk_product;
- }
- } else {
- foreach ($objectLines as $line) {
- if ($line->fk_product) {
- $productIdArray[] = $line->fk_product;
- }
- }
- }
- $nboflot = $this->loadLotStock($productIdArray);
- $out .= '<datalist id="'.$htmlname.'" >';
- if (!empty($fk_product) && $fk_product > 0) {
- $productIdArray = array((int) $fk_product); // only show lot stock for product
- } else {
- foreach ($this->cache_lot as $key => $value) {
- $productIdArray[] = $key;
- }
- }
- foreach ($productIdArray as $productId) {
- if (array_key_exists($productId, $this->cache_lot)) {
- foreach ($this->cache_lot[$productId] as $id => $arraytypes) {
- if (empty($fk_entrepot) || $fk_entrepot == $arraytypes['entrepot_id']) {
- $label = $arraytypes['entrepot_label'] . ' - ';
- $label .= $arraytypes['batch'];
- $out .= '<option>' . $arraytypes['batch'] . '</option>';
- }
- }
- }
- }
- $out .= '</datalist>';
- return $out;
- }
- /**
- * Load in cache array list of lot available in stock from a given list of products
- *
- * @param array $productIdArray array of product id's from who to get lot numbers. A
- *
- * @return int Nb of loaded lines, 0 if nothing loaded, <0 if KO
- */
- private function loadLotStock($productIdArray = array())
- {
- global $conf, $langs;
- $cacheLoaded = false;
- if (empty($productIdArray)) {
- // only Load lot stock for given products
- $this->cache_lot = array();
- return 0;
- }
- if (count($productIdArray) && count($this->cache_lot)) {
- // check cache already loaded for product id's
- foreach ($productIdArray as $productId) {
- $cacheLoaded = !empty($this->cache_lot[$productId]) ? true : false;
- }
- }
- if ($cacheLoaded) {
- return count($this->cache_lot);
- } else {
- // clear cache
- $this->cache_lot = array();
- $productIdList = implode(',', $productIdArray);
- $sql = "SELECT pb.batch, pb.rowid, ps.fk_entrepot, pb.qty, e.ref as label, ps.fk_product";
- $sql .= " FROM ".$this->db->prefix()."product_batch as pb";
- $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.rowid = pb.fk_product_stock";
- $sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on e.rowid = ps.fk_entrepot AND e.entity IN (".getEntity('stock').")";
- if (!empty($productIdList)) {
- $sql .= " WHERE ps.fk_product IN (".$this->db->sanitize($productIdList).")";
- }
- $sql .= " ORDER BY e.ref, pb.batch";
- dol_syslog(get_class($this).'::loadLotStock', LOG_DEBUG);
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- $i = 0;
- while ($i < $num) {
- $obj = $this->db->fetch_object($resql);
- $this->cache_lot[$obj->fk_product][$obj->rowid]['id'] = $obj->rowid;
- $this->cache_lot[$obj->fk_product][$obj->rowid]['batch'] = $obj->batch;
- $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_id'] = $obj->fk_entrepot;
- $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_label'] = $obj->label;
- $this->cache_lot[$obj->fk_product][$obj->rowid]['qty'] = $obj->qty;
- $i++;
- }
- return $num;
- } else {
- dol_print_error($this->db);
- return -1;
- }
- }
- }
- }
|