From 651ea926571ecc954c2caa3c5a109d7462e94945 Mon Sep 17 00:00:00 2001 From: alexis portable Date: Tue, 9 May 2017 14:26:47 +0200 Subject: [PATCH] NEW fix listview class and add a demo for product list --- htdocs/product/inventory/listview.class.php | 221 +++--- htdocs/product/list-with-listview.php | 702 ++++++++++++++++++++ 2 files changed, 834 insertions(+), 89 deletions(-) create mode 100644 htdocs/product/list-with-listview.php diff --git a/htdocs/product/inventory/listview.class.php b/htdocs/product/inventory/listview.class.php index 51855629686..1c03d0b524f 100644 --- a/htdocs/product/inventory/listview.class.php +++ b/htdocs/product/inventory/listview.class.php @@ -39,6 +39,8 @@ class Listview $this->form = null; $this->totalRowToShow=0; $this->totalRow=0; + + $this->TField=array(); } /** @@ -70,14 +72,15 @@ class Listview ,'head_search'=>'' ,'export'=>array() ,'view_type'=>'' + ,'massactions'=>array() ),$TParam['list']); if (empty($TParam['limit'])) $TParam['limit'] = array(); $page = GETPOST('page'); - if (!empty($page)) $TParam['limit']['page'] = $page+1; // TODO dolibarr start page at 0 instead 1 + if (!empty($page)) $TParam['limit']['page'] = $page; - $TParam['limit'] = array_merge(array('page'=>1, 'nbLine' => $conf->liste_limit, 'global'=>0), $TParam['limit']); + $TParam['limit'] = array_merge(array('page'=>0, 'nbLine' => $conf->liste_limit, 'global'=>0), $TParam['limit']); if (GETPOST('sortfield')) { @@ -137,17 +140,6 @@ class Listview return $TKey; } - - /** - * @param timestamp $date date to convert - * @return int|string Date TMS or '' - */ - private function dateToSQLDate($date) - { - return $this->db->idate($date); - } - - /** * @param string $TSQLMore contain some additional sql instructions * @param string $value date with read format @@ -160,13 +152,11 @@ class Listview $TSQLDate=array(); if(!empty($value['start'])) { -// $valueDeb = $this->dateToSQLDate($value['start'].' 00:00:00'); $TSQLDate[]=$sKey." >= '".$value['start']."'" ; } if(!empty($value['end'])) { -// $valueFin = $this->dateToSQLDate($value['end'].' 23:59:59'); $TSQLDate[]=$sKey." <= '".$value['end']."'" ; } @@ -174,7 +164,6 @@ class Listview } else { -// $value = $this->dateToSQLDate($value); $TSQLMore[]=$sKey." LIKE '".$value."%'" ; } } @@ -227,9 +216,7 @@ class Listview */ private function search($sql, &$TParam) { - $ListPOST = GETPOST('Listview'); - - if (!GETPOST("button_removefilter_x") && !GETPOST("button_removefilter.x") && !GETPOST("button_removefilter")) + if (empty($TParam['no-auto-sql-search']) && !GETPOST("button_removefilter_x") && !GETPOST("button_removefilter.x") && !GETPOST("button_removefilter")) { foreach ($TParam['search'] as $field => $info) { @@ -237,12 +224,14 @@ class Listview $TSQLMore = array(); $allow_is_null = $this->getSearchNull($field,$TParam); + $fieldname = !empty($info['fieldname']) ? $info['fieldname'] : 'Listview_'.$this->id.'_search_'.$field; + foreach ($TsKey as $i => &$sKey) { - $value = ''; - if (isset($ListPOST[$this->id]['search'][$field])) $value = $ListPOST[$this->id]['search'][$field]; + $value = GETPOST($fieldname); + $value_null = GETPOST('Listview_'.$this->id.'_search_on_null_'.$field); - if ($allow_is_null && !empty($ListPOST[$this->id]['search_on_null'][$field])) + if ($allow_is_null && !empty($value_null)) { $TSQLMore[] = $sKey.' IS NULL '; $value = ''; @@ -250,7 +239,7 @@ class Listview if (isset($TParam['type'][$field]) && ($TParam['type'][$field]==='date' || $TParam['type'][$field]==='datetime')) { - $k = 'Listview_'.$this->id.'_search_'.$field; + $k = $fieldname; if ($info['search_type'] === 'calendars') { $value = array(); @@ -296,25 +285,22 @@ class Listview { global $conf; - $TField=array(); + $TField= & $this->TField; $this->init($TParam); $THeader = $this->initHeader($TParam); $sql = $this->search($sql,$TParam); - $sql.= $this->db->order($TParam['param']['sortfield'], $TParam['param']['sortorder']); - - $nbtotalofrecords = ''; + $sql.= $this->db->order($TParam['sortfield'], $TParam['sortorder']); + if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $result = $this->db->query($sql); - $nbtotalofrecords = $this->db->num_rows($result); + $this->totalRow = $this->db->num_rows($result); } - $sql.= $this->db->plimit($TParam['param']['limit'] + 1, $TParam['param']['offset']); $this->parse_sql($THeader, $TField, $TParam, $sql); - list($TTotal, $TTotalGroup)=$this->get_total($TField, $TParam); return $this->renderList($THeader, $TField, $TTotal, $TTotalGroup, $TParam); @@ -335,44 +321,42 @@ class Listview $nb_search_in_bar = 0; - if(!empty($TParam['search'])) + foreach($THeader as $key => $libelle) { - foreach($THeader as $key => $libelle) - { - if(empty($TSearch[$key]))$TSearch[$key]=''; - } - } + if(empty($TSearch[$key]))$TSearch[$key]=''; + } - $ListPOST = GETPOST('Listview'); $removeFilter = (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")); foreach($TParam['search'] as $key => $param_search) { - $value = isset($ListPOST[$this->id]['search'][$key]) ? $ListPOST[$this->id]['search'][$key] : ''; if ($removeFilter) $value = ''; $typeRecherche = (is_array($param_search) && isset($param_search['search_type'])) ? $param_search['search_type'] : $param_search; + $fieldname = !empty($param_search['fieldname']) ? $param_search['fieldname'] : 'Listview_'.$this->id.'_search_'.$key; + $value = $removeFilter ? '' : GETPOST($fieldname); + if(is_array($typeRecherche)) { - $fsearch=$form->selectarray('Listview['.$this->id.'][search]['.$key.']', $typeRecherche,$value,1); + $fsearch=$form->selectarray($fieldname, $typeRecherche,$value,1); } else if($typeRecherche==='calendar') { - if (!$removeFilter) $value = GETPOST('Listview_'.$this->id.'_search_'.$key) ? mktime(0,0,0, (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'month'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'day'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'year') ) : ''; + if (!$removeFilter) $value = GETPOST($fieldname) ? mktime(0,0,0, (int) GETPOST($fieldname.'month'), (int) GETPOST($fieldname.$key.'day'), (int) GETPOST($fieldname.'year') ) : ''; - $fsearch = $form->select_date($value, 'Listview_'.$this->id.'_search_'.$key,0, 0, 1, "", 1, 0, 1); + $fsearch = $form->select_date($value, $fieldname,0, 0, 1, "", 1, 0, 1); } else if($typeRecherche==='calendars') { $value_start = $value_end = ''; if (!$removeFilter) { - $value_start = GETPOST('Listview_'.$this->id.'_search_'.$key.'_start') ? mktime(0,0,0, (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_startmonth'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_startday'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_startyear') ) : ''; - $value_end = GETPOST('Listview_'.$this->id.'_search_'.$key.'_end') ? mktime(0,0,0, (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_endmonth'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_endday'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_endyear') ) : ''; + $value_start = GETPOST($fieldname.'_start') ? mktime(0,0,0, (int) GETPOST($fieldname.'_startmonth'), (int) GETPOST($fieldname.'_startday'), (int) GETPOST($fieldname.'_startyear') ) : ''; + $value_end = GETPOST($fieldname.'_end') ? mktime(0,0,0, (int) GETPOST($fieldname.'_endmonth'), (int) GETPOST($fieldname.'_endday'), (int) GETPOST($fieldname.'_endyear') ) : ''; } - $fsearch = $form->select_date($value_start, 'Listview_'.$this->id.'_search_'.$key.'_start',0, 0, 1, "", 1, 0, 1) - . $form->select_date($value_end, 'Listview_'.$this->id.'_search_'.$key.'_end',0, 0, 1, "", 1, 0, 1); + $fsearch = $form->select_date($value_start,$fieldname.'_start',0, 0, 1, "", 1, 0, 1) + . $form->select_date($value_end, $fieldname.'_end',0, 0, 1, "", 1, 0, 1); } else if(is_string($typeRecherche)) @@ -381,13 +365,13 @@ class Listview } else { - $fsearch=''; + $fsearch=''; } if(!empty($param_search['allow_is_null'])) { - $valueNull = isset($ListPOST[$this->id]['search_on_null'][$key]) ? 1 : 0; - $fsearch.=' '.$form->checkbox1('', 'Listview['.$this->id.'][search_on_null]['.$key.']',1, $valueNull,' onclick=" if($(this).is(\':checked\')){ $(this).prev().val(\'\'); }" ').img_help(1, $langs->trans('SearchOnNUllValue')); + $valueNull = GETPOST($fieldname.'search_on_null_'.$key) ? 1 : 0; + $fsearch.=' '.$form->checkbox1('', $fieldname.'search_on_null_'.$key,1, $valueNull,' onclick=" if($(this).is(\':checked\')){ $(this).prev().val(\'\'); }" ').img_help(1, $langs->trans('SearchOnNUllValue')); } if(!empty($THeader[$key])) @@ -395,20 +379,10 @@ class Listview $TSearch[$key] = $fsearch; $nb_search_in_bar++; } - else - { - $label = !empty($TParam['title'][$key]) ? $TParam['title'][$key] : $key ; - $TParam['list']['head_search'].= ''.$label.''; -// $TParam['list']['head_search'].='
'.$label.' '.$fsearch.'
'; - } } $search_button = ' '.img_search().''; - - if(!empty($TParam['list']['head_search'])) - { - $TParam['list']['head_search']='
'.$search_button.'
'.$TParam['list']['head_search']; - } + $search_button .= ' '.img_searchclear().''; if($nb_search_in_bar>0) { @@ -603,7 +577,7 @@ class Listview */ private function renderList(&$THeader, &$TField, &$TTotal, &$TTotalGroup, &$TParam) { - global $bc; + global $bc,$form; $TSearch = $this->setSearch($THeader, $TParam); $TExport = $this->setExport($TParam, $TField, $THeader); @@ -611,13 +585,24 @@ class Listview //$out = $this->getJS(); + $massactionbutton= empty($TParam['list']['massactions']) ? '' : $form->selectMassAction('', $TParam['list']['massactions']); + $dolibarr_decalage = $this->totalRow > $this->totalRowToShow ? 1 : 0; ob_start(); - print_barre_liste($TParam['list']['title'], $TParam['limit']['page']-1, $_SERVER["PHP_SELF"], '&'.$TParam['list']['param_url'], $TParam['sortfield'], $TParam['sortorder'], '', $this->totalRowToShow+$dolibarr_decalage, $this->totalRow, $TParam['list']['image'], 0, '', '', $TParam['limit']['nbLine']); + print_barre_liste($TParam['list']['title'], $TParam['limit']['page'], $_SERVER["PHP_SELF"], '&'.$TParam['list']['param_url'], $TParam['sortfield'], $TParam['sortorder'], $massactionbutton, $this->totalRowToShow+$dolibarr_decalage, $this->totalRow, $TParam['list']['image'], 0, '', '', $TParam['limit']['nbLine']); $out .= ob_get_clean(); + $classliste='liste'; + if(!empty($TParam['head_search'])) { + $out.='
'; + $out.=$TParam['head_search']; + $out.='
'; + + $classliste.=' listwithfilterbefore'; + } - $out.= ''; + $out.= '
'; + $out.= '
'; if(count($TSearch)>0) { @@ -627,12 +612,12 @@ class Listview { if ($field === 'selectedfields') { - $out.= ''; + $out.= ''; } else { $moreattrib = 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"'; - $out .= ''; + $out .= ''; } } @@ -646,10 +631,17 @@ class Listview $search = ''; $prefix = ''; + $label = $head['label']; + if ($field === 'selectedfields') { $moreattrib = 'align="right" '; $prefix = 'maxwidthsearch '; + + if(!empty($TParam['list']['massactions'])) { + $label.=$form->showCheckAddButtons('checkforselect', 1); + } + } if (empty($head['width'])) $head['width'] = 'auto'; @@ -662,10 +654,10 @@ class Listview else $search = $field; } - $out .= getTitleFieldOfList($head['label'], 0, $_SERVER["PHP_SELF"], $search, '', $moreparam, $moreattrib, $TParam['sortfield'], $TParam['sortorder'], $prefix); + $out .= getTitleFieldOfList($label, 0, $_SERVER["PHP_SELF"], $search, '', $moreparam, $moreattrib, $TParam['sortfield'], $TParam['sortorder'], $prefix); $out .= $head['more']; } - + //$out .= ''; $out .= ''; @@ -673,23 +665,34 @@ class Listview if(empty($TField)) { - if (!empty($TParam['list']['messageNothing'])) $out .= ''; + if (!empty($TParam['list']['messageNothing'])) $out .= ''; } else { - $var=true; $line_number = 0; foreach($TField as $fields) { if($this->in_view($TParam, $line_number)) { - $var=!$var; - $out.=''; + $out.=''; foreach ($THeader as $field => $head) { + $value_aff =(isset($fields[$field]) ? $fields[$field] : ' '); + + if ($field === 'selectedfields') + { + $head['text-align']='center'; + if(!empty($TParam['list']['massactions'])) { + $arrayofselected=array(); // TODO get in param + $selected=0; + if (in_array($obj->rowid, $arrayofselected)) $selected=1; + $value_aff.=''; + } + } + $moreattrib = 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"'; - $out.=''; + $out.=''; } $out.=''; @@ -718,6 +721,7 @@ class Listview } $out .= '
'.$this->form->showFilterAndCheckAddButtons(0).''.$this->form->showFilterAndCheckAddButtons(0).''.$TSearch[$field].''.$TSearch[$field].'--
'.$TParam['list']['messageNothing'].'
'.$TParam['list']['messageNothing'].'
'.$fields[$field].''.$value_aff.'
'; + $out .= ''; return $out; } @@ -760,7 +764,7 @@ class Listview foreach($TField as $row) { - $this->set_line($TField, $TParam, $row); + $this->set_line($THeader, $TField, $TParam, $row); } } @@ -778,7 +782,7 @@ class Listview } $contextpage=md5($_SERVER['PHP_SELF']); - if(!empty($TParam['allow-field-select'])) + if(!empty($TParam['allow-fields-select'])) { $selectedfields = GETPOST('Listview'.$this->id.'_selectedfields'); @@ -839,18 +843,25 @@ class Listview 'order'=>(in_array($field, $TParam['orderby']['noOrder']) ? 0 : 1), 'width'=>(!empty($TParam['size']['width'][$field]) ? $TParam['size']['width'][$field] : 'auto'), 'text-align'=>(!empty($TParam['position']['text-align'][$field]) ? $TParam['position']['text-align'][$field] : 'auto'), + 'rank'=>(!empty($TParam['position']['rank'][$field]) ? $TParam['position']['rank'][$field] : 0), 'more'=>'' ); } } - if(!empty($selectedfields)) - { - $THeader['selectedfields']['label']='
'.$selectedfields.'
'; - } + uasort($THeader,array('Listview','sortHeaderRank')); + + $THeader['selectedfields']['label']=$selectedfields; return $THeader; } + + public function sortHeaderRank(&$a, &$b) { + if($a['rank']>$b['rank']) return 1; + else if($a['rank']<$b['rank']) return -1; + else return 0; + + } /** * @param string $TParam TParam @@ -874,11 +885,14 @@ class Listview } /** - * @param string $TField TField - * @param string $TParam TParam - * @param string $currentLine aaa + * Apply function to result and set fields array + * + * @param string $THeader array of headers + * @param string $TField array of fields + * @param string $TParam array of parameters + * @param string $currentLine object containing current sql result */ - private function set_line(&$TField, &$TParam, $currentLine) + private function set_line(&$THeader, &$TField, &$TParam, $currentLine) { global $conf; @@ -887,16 +901,21 @@ class Listview if($this->in_view($TParam,$line_number)) { $this->totalRowToShow++; - $row=array(); $trans = array(); - foreach($currentLine as $field=>$value) + $row=array(); + $trans = array(); + foreach($currentLine as $kF=>$vF)$trans['@'.$kF.'@'] = addslashes($vF); + + foreach($THeader as $field=>$dummy) { + $value = isset($currentLine->{$field}) ? $currentLine->{$field}: ''; + if(is_object($value)) { if(get_class($value)=='stdClass') {$value=print_r($value, true);} else $value=(string) $value; } - $trans['@'.$field.'@'] = $value; + $trans['@'.$field.'@'] = addslashes($value); if(!empty($TParam['math'][$field])) { @@ -910,17 +929,19 @@ class Listview if(isset($TParam['eval'][$field]) && in_array($field,array_keys($row))) { - $strToEval = 'return '.strtr( $TParam['eval'][$field], array_merge( $trans, array('@val@'=>$row[$field]) )).';'; + $strToEval = 'return '.strtr( $TParam['eval'][$field], array_merge( $trans, array('@val@'=>addslashes( $row[$field] )) )).';'; $row[$field] = eval($strToEval); + } if(isset($TParam['type'][$field]) && !isset($TParam['eval'][$field])) { if($TParam['type'][$field]=='date' || $TParam['type'][$field]=='datetime' ) { + if($row[$field] != '0000-00-00 00:00:00' && $row[$field] != '1000-01-01 00:00:00' && $row[$field] != '0000-00-00' && !empty($row[$field])) { - if($TParam['type'][$field]=='datetime')$row[$field] = dol_print_date(strtotime($row[$field]),'dayhoursec'); + if($TParam['type'][$field]=='datetime')$row[$field] = dol_print_date(strtotime($row[$field]),'dayhour'); else $row[$field] = dol_print_date(strtotime($row[$field]),'day'); } else @@ -996,6 +1017,8 @@ class Listview { $sql.=' LIMIT '.(int) $TParam['limit']['global']; } + else if(!empty($TParam['limit'])) $sql.= $this->db->plimit($TParam['limit']['nbLine']+1, $TParam['limit']['page'] * $TParam['limit']['nbLine']); + return $sql; } @@ -1008,7 +1031,7 @@ class Listview */ private function parse_sql(&$THeader, &$TField, &$TParam, $sql) { - $this->sql = $this->limitSQL($sql, $TParam); + $this->sql = $this->limitSQL($sql, $TParam); $this->TTotalTmp=array(); $this->THideFlip = array_flip($TParam['hide']); @@ -1016,12 +1039,13 @@ class Listview $res = $this->db->query($this->sql); if($res!==false) { - $this->totalRow = $this->db->num_rows($res); dol_syslog(get_class($this)."::parse_sql id=".$this->id." sql=".$this->sql, LOG_DEBUG); + if(empty($this->totalRow))$this->totalRow = $this->db->num_rows($res); + while($currentLine = $this->db->fetch_object($res)) { - $this->set_line($TField, $TParam, $currentLine); + $this->set_line($THeader, $TField, $TParam, $currentLine); } } else @@ -1029,4 +1053,23 @@ class Listview dol_syslog(get_class($this)."::parse_sql id=".$this->id." sql=".$this->sql, LOG_ERR); } } + + static function getCachedOjbect($class_name, $fk_object) { + global $db, $TCacheListObject; + + if(!class_exists($class_name)) return false; + + if(empty($TCacheListObject)) $TCacheListObject = array(); + if(empty($TCacheListObject[$class_name])) $TCacheListObject[$class_name] =array(); + + if(empty($TCacheListObject[$class_name][$fk_object])) { + $TCacheListObject[$class_name][$fk_object]= new $class_name($db); + if( $TCacheListObject[$class_name][$fk_object]->fetch($fk_object)<0) { + return false; + } + } + + return $TCacheListObject[$class_name][$fk_object]; + } + } diff --git a/htdocs/product/list-with-listview.php b/htdocs/product/list-with-listview.php new file mode 100644 index 00000000000..8d53496dbcb --- /dev/null +++ b/htdocs/product/list-with-listview.php @@ -0,0 +1,702 @@ + + * Copyright (C) 2004-2016 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2012-2016 Marcos García + * Copyright (C) 2013-2016 Juanjo Menent + * Copyright (C) 2013-2015 Raphaël Doursenaud + * Copyright (C) 2013 Jean Heimburger + * Copyright (C) 2013 Cédric Salvador + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2013 Adolfo segura + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2016 Ferran Marcet + * + * 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 . + */ + +/** + * \file htdocs/product/list.php + * \ingroup produit + * \brief Page to list products and services + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/inventory/listview.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +if (! empty($conf->categorie->enabled)) + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; + +$langs->load("products"); +$langs->load("stocks"); +$langs->load("suppliers"); +$langs->load("companies"); +if (! empty($conf->productbatch->enabled)) $langs->load("productbatch"); + +$action=GETPOST('action','alpha'); +$massaction=GETPOST('massaction','alpha'); +$show_files=GETPOST('show_files','int'); +$confirm=GETPOST('confirm','alpha'); +$toselect = GETPOST('toselect', 'array'); + +$sref=GETPOST("sref"); +$sbarcode=GETPOST("sbarcode"); +$snom=GETPOST("snom"); +$sall=GETPOST("sall"); +$type= (int) GETPOST("type","int"); +$search_sale = GETPOST("search_sale"); +$search_categ = GETPOST("search_categ",'int'); +$tosell = GETPOST("tosell", 'int'); +$tobuy = GETPOST("tobuy", 'int'); +$fourn_id = GETPOST("fourn_id",'int'); +$catid = GETPOST('catid','int'); +$search_tobatch = GETPOST("search_tobatch",'int'); +$search_accountancy_code_sell = GETPOST("search_accountancy_code_sell",'alpha'); +$search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha'); +$optioncss = GETPOST('optioncss','alpha'); + +//Show/hide child products. Hidden by default +if (!$_POST) { + $search_hidechildproducts = 'on'; +} else { + $search_hidechildproducts = GETPOST('search_hidechildproducts'); +} + +$diroutputmassaction=$conf->product->dir_output . '/temp/massgeneration/'.$user->id; + +$limit = GETPOST("limit")?GETPOST("limit","int"):$conf->liste_limit; +$sortfield = GETPOST("sortfield",'alpha'); +$sortorder = GETPOST("sortorder",'alpha'); +$page = (GETPOST("page",'int')?GETPOST("page", 'int'):0); +if ($page == -1) { $page = 0; } +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (! $sortfield) $sortfield="p.ref"; +if (! $sortorder) $sortorder="ASC"; + +// Initialize context for list +$contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'productservicelist'; +if ((string) $type == '1') { $contextpage='servicelist'; if ($search_type=='') $search_type='1'; } +if ((string) $type == '0') { $contextpage='productlist'; if ($search_type=='') $search_type='0'; } + +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +$hookmanager->initHooks(array($contextpage)); +$extrafields = new ExtraFields($db); +$form=new Form($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('product'); +$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_'); + +if (empty($action)) $action='list'; + +// Get object canvas (By default, this is not defined, so standard usage of dolibarr) +$canvas=GETPOST("canvas"); +$objcanvas=null; +if (! empty($canvas)) +{ + require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php'; + $objcanvas = new Canvas($db,$action); + $objcanvas->getCanvas('product','list',$canvas); +} + +// Security check +if ($type=='0') $result=restrictedArea($user,'produit','','','','','',$objcanvas); +else if ($type=='1') $result=restrictedArea($user,'service','','','','','',$objcanvas); +else $result=restrictedArea($user,'produit|service','','','','','',$objcanvas); + +// Define virtualdiffersfromphysical +$virtualdiffersfromphysical=0; +if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) +{ + $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array( + 'p.ref'=>"Ref", + 'pfp.ref_fourn'=>"RefSupplier", + 'p.label'=>"ProductLabel", + 'p.description'=>"Description", + "p.note"=>"Note", +); +// multilang +if (! empty($conf->global->MAIN_MULTILANGS)) +{ + $fieldstosearchall['pl.label']='ProductLabelTranslated'; + $fieldstosearchall['pl.description']='ProductDescriptionTranslated'; + $fieldstosearchall['pl.note']='ProductNoteTranslated'; +} +if (! empty($conf->barcode->enabled)) { + $fieldstosearchall['p.barcode']='Gencod'; +} + +if (empty($conf->global->PRODUIT_MULTIPRICES)) +{ + $titlesellprice=$langs->trans("SellingPrice"); + if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES)) + { + $titlesellprice=$form->textwithpicto($langs->trans("SellingPrice"), $langs->trans("DefaultPriceRealPriceMayDependOnCustomer")); + } +} + +// Definition of fields for lists +$arrayfields=array( + 'p.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1), + //'pfp.ref_fourn'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))), + 'p.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1), + 'p.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>($contextpage != 'servicelist'), 'enabled'=>(! empty($conf->barcode->enabled))), + 'p.duration'=>array('label'=>$langs->trans("Duration"), 'checked'=>($contextpage != 'productlist'), 'enabled'=>(! empty($conf->service->enabled))), + 'p.price'=>array('label'=>$langs->trans("SellingPrice"), 'checked'=>1, 'enabled'=>empty($conf->global->PRODUIT_MULTIPRICES)), + 'p.minbuyprice'=>array('label'=>$langs->trans("BuyingPriceMinShort"), 'checked'=>1, 'enabled'=>(! empty($user->rights->fournisseur->lire))), + 'p.seuil_stock_alerte'=>array('label'=>$langs->trans("StockLimit"), 'checked'=>0, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')), + 'p.desiredstock'=>array('label'=>$langs->trans("DesiredStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')), + 'p.stock'=>array('label'=>$langs->trans("PhysicalStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')), + 'stock_virtual'=>array('label'=>$langs->trans("VirtualStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service' && $virtualdiffersfromphysical)), + 'p.tobatch'=>array('label'=>$langs->trans("ManageLotSerial"), 'checked'=>0, 'enabled'=>(! empty($conf->productbatch->enabled))), + 'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0), + 'p.accountancy_code_buy'=>array('label'=>$langs->trans("ProductAccountancyBuyCode"), 'checked'=>0), + 'p.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500), + 'p.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500), + 'p.tosell'=>array('label'=>$langs->trans("Status").' ('.$langs->trans("Sell").')', 'checked'=>1, 'position'=>1000), + 'p.tobuy'=>array('label'=>$langs->trans("Status").' ('.$langs->trans("Buy").')', 'checked'=>1, 'position'=>1000) +); +// Extra fields +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) +{ + foreach($extrafields->attribute_label as $key => $val) + { + $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key]); + } +} + + + +/* + * Actions + */ + +if (GETPOST('cancel')) { $action='list'; $massaction=''; } +if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; } + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions',$parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers + { + $sall=""; + $sref=""; + $snom=""; + $sbarcode=""; + $search_categ=0; + $tosell=""; + $tobuy=""; + $search_tobatch=''; + $search_accountancy_code_sell=''; + $search_accountancy_code_buy=''; + $search_array_options=array(); + } + + // Mass actions + $objectclass='Product'; + if ((string) $type == '1') { $objectlabel='Services'; } + if ((string) $type == '0') { $objectlabel='Products'; } + + $permtoread = $user->rights->produit->lire; + $permtodelete = $user->rights->produit->supprimer; + $uploaddir = $conf->product->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + +/* + * View + */ + +$htmlother=new FormOther($db); + +if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) +{ + $objcanvas->assign_values($action); // This must contains code to load data (must call LoadListDatas($limit, $offset, $sortfield, $sortorder)) + $objcanvas->display_canvas($action); // This is code to show template +} +else +{ + $title=$langs->trans("ProductsAndServices"); + + if (isset($type)) + { + if ($type==1) + { + $texte = $langs->trans("Services"); + } + else + { + $texte = $langs->trans("Products"); + } + } + else + { + $texte = $langs->trans("ProductsAndServices"); + } + + $sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,'; + $sql.= ' p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,'; + $sql.= ' p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy,'; + $sql.= ' p.datec, p.tms,'; + //$sql.= ' pfp.ref_fourn as ref_supplier, '; + $sql.= ' MIN(pfp.unitprice) as minsellprice'; + if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) { + $sql .= ', pac.rowid prod_comb_id'; + } + // Add fields from extrafields + foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : ''); + // Add fields from hooks + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters); // Note that $action and $object may have been modified by hook + $sql.=$hookmanager->resPrint; + $sql.= ' FROM '.MAIN_DB_PREFIX.'product as p'; + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_extrafields as ef on (p.rowid = ef.fk_object)"; + if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_product as cp ON p.rowid = cp.fk_product"; // We'll need this table joined to the select in order to filter by categ + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product"; + // multilang + if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang = '".$langs->getDefaultLang() ."'"; + if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) { + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid"; + } + + $sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')'; + if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall); + // if the type is not 1, we show all products (type = 0,2,3) + if (dol_strlen($type)) + { + if ($type == 1) $sql.= " AND p.fk_product_type = '1'"; + else $sql.= " AND p.fk_product_type <> '1'"; + } + if ($sref) $sql .= natural_search('p.ref', $sref); + if ($snom) $sql .= natural_search('p.label', $snom); + if ($sbarcode) $sql .= natural_search('p.barcode', $sbarcode); + if (isset($tosell) && dol_strlen($tosell) > 0 && $tosell!=-1) $sql.= " AND p.tosell = ".$db->escape($tosell); + if (isset($tobuy) && dol_strlen($tobuy) > 0 && $tobuy!=-1) $sql.= " AND p.tobuy = ".$db->escape($tobuy); + if (dol_strlen($canvas) > 0) $sql.= " AND p.canvas = '".$db->escape($canvas)."'"; + if ($catid > 0) $sql.= " AND cp.fk_categorie = ".$catid; + if ($catid == -2) $sql.= " AND cp.fk_categorie IS NULL"; + if ($search_categ > 0) $sql.= " AND cp.fk_categorie = ".$db->escape($search_categ); + if ($search_categ == -2) $sql.= " AND cp.fk_categorie IS NULL"; + if ($fourn_id > 0) $sql.= " AND pfp.fk_soc = ".$fourn_id; + if ($search_tobatch != '' && $search_tobatch >= 0) $sql.= " AND p.tobatch = ".$db->escape($search_tobatch); + if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell); + if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy); + // Add where from extra fields + + if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) { + $sql .= " AND pac.rowid IS NULL"; + } + + // Add where from extra fields + foreach ($search_array_options as $key => $val) + { + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + $typ=$extrafields->attribute_type[$tmpkey]; + $mode=0; + if (in_array($typ, array('int','double'))) $mode=1; // Search on a numeric + if ($val && ( ($crit != '' && ! in_array($typ, array('select'))) || ! empty($crit))) + { + $sql .= natural_search('ef.'.$tmpkey, $crit, $mode); + } + } + // Add where from hooks + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters); // Note that $action and $object may have been modified by hook + $sql.=$hookmanager->resPrint; + $sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,"; + $sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,"; + $sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy'; + if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) { + $sql .= ', pac.rowid'; + } + // Add fields from extrafields + foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key : ''); + // Add fields from hooks + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldSelect',$parameters); // Note that $action and $object may have been modified by hook + $sql.=$hookmanager->resPrint; + + // TODO put these functions into product.lib.php if this go from demo to core + /** + * Function return formated sell price + * + * @param int $fk_object rowid of product + * @return string + */ + function list_get_product_sellprice($fk_object) { + global $langs,$conf, $user; + + $object = Listview::getCachedOjbect('Product', $fk_object); + if($object === false) return ''; + + if ($object->status) + { + if ($object->price_base_type == 'TTC') return price($object->price_ttc).' '.$langs->trans("TTC"); + else return price($object->price).' '.$langs->trans("HT"); + } + return ''; + } + + /** + * Function return formated product status sell or buy + * + * @param int $fk_object rowid of product + * @param string $field concerned field status|status_buy + * @param int $type for libstatus + * @return string + */ + function list_get_product_status($fk_object, $field, $type) { + global $conf, $user; + + $object = Listview::getCachedOjbect('Product', $fk_object); + + if($object === false) return ''; + + if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) { + return ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell'); + } else { + return $object->LibStatut($object->{$field},5,$type); + } + + } + + /** + * Function return formated ref + * + * @param int $fk_object rowid of product + * @return string + */ + function list_get_product_ref($fk_object) { + global $conf, $user; + + $object = Listview::getCachedOjbect('Product', $fk_object); + + if($object === false) return ''; + + return $object->getNomUrl(1,'',24); + } + + /** + * Function return formated extrafield + * + * @param int $fk_object rowid of product + * @param string $key extrafield to output + * @return string + */ + function list_get_product_extrafield($fk_object, $key) { + global $extrafields; + + $object = Listview::getCachedOjbect('Product', $fk_object); + if($object === false) return ''; + + return $extrafields->showOutputField($key, $object->array_options['options_'.$key], '', 1); + } + + /** + * Function return formated virtual stock + * + * @param int $fk_object rowid of product + * @return string + */ + function list_get_product_virtual_stock($fk_object) { + global $langs; + + $object = Listview::getCachedOjbect('Product', $fk_object); + if($object === false) return ''; + + $object->load_stock('nobatch'); + + $out = ''; + if ($object->type != 1) + { + if ($object->seuil_stock_alerte != '' && $object->stock_theorique < (float) $object->seuil_stock_alerte) $out.= img_warning($langs->trans("StockTooLow")).' '; + $out.= $object->stock_theorique; + } + + return $out; + } + + /** + * Function return formated stock + * + * @param int $fk_object rowid of product + * @return string + */ + function list_get_product_stock($fk_object) { + global $langs; + + $object = Listview::getCachedOjbect('Product', $fk_object); + if($object === false) return ''; + + $out = ''; + if ($object->type != 1) + { + if ($object->seuil_stock_alerte != '' && $object->stock_reel< (float) $object->seuil_stock_alerte) $out.= img_warning($langs->trans("StockTooLow")).' '; + $out.= (double)$object->stock_reel; + } + + return $out; + } + /** + * Function return formated min buy price + * + * @param int $fk_object rowid of product + * @return string + */ + function list_get_product_minbuyprice($fk_object) { + global $conf, $user, $langs,$db,$form; + + $out = ''; + + $object = Listview::getCachedOjbect('Product', $fk_object); + if($object === false || empty($object->status_buy) ) return ''; + + $product_fourn =new ProductFournisseur($db); + if ($product_fourn->find_min_price_product_fournisseur($fk_object) > 0) + { + if ($product_fourn->product_fourn_price_id > 0) + { + if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire) + { + $htmltext=$product_fourn->display_price_product_fournisseur(1, 1, 0, 1); + $out.= $form->textwithpicto(price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"),$htmltext); + } + else $out.= price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"); + } + } + return $out; + } + + // array of customized field function + $arrayeval = array( + 'tobuy'=>'list_get_product_status(@rowid@, "status_buy",1)' + ,'tosell'=>'list_get_product_status(@rowid@, "status",0)' + ,'ref'=>'list_get_product_ref(@rowid@)' + ,'label'=>'dol_trunc("@val@",40)' + ,'price'=>'list_get_product_sellprice(@rowid@)' + ,'stock_virtual'=>'list_get_product_virtual_stock(@rowid@)' + ,'stock'=>'list_get_product_stock(@rowid@)' + ,'minbuyprice'=>'list_get_product_minbuyprice(@rowid@)' + ); + + // defined list align for field + $arrayalign = array( + 'price'=>'right' + ,'tobuy'=>'right' + ,'tosell'=>'right' + ,'desiredstock'=>'right' + ,'stock'=>'right' + ,'stock_virtual'=>'right' + ,'minbuyprice'=>'right' + ,'datec'=>'center' + ,'tms'=>'center' + ); + + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListMoreFields',$parameters); // Note that $action and $object may have been modified by hook + if($reshook) { + $arrayfields = $hookmanager->resArray; + } + + // init title, hidden field (allowed into selected fields), and position + $arrayhide = $arraytitle = $arrayposition = array(); + foreach($arrayfields as $k=>$data) { + if(!isset($data['enabled']) || $data['enabled']) { + list($t,$f) = explode('.',$k); + if(empty($f))$f = $k; + $arraytitle[$f]=$data['label']; + if(empty($data['checked'])) $arrayhide[] = $f; + $arrayposition[$f] = empty($data['position']) ? 0 : $data['position']; + } + } + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + $arrayalign[$key]=$extrafields->getAlignFlag($key); + $arrayeval[$key] = 'list_get_product_extrafield(@rowid@, "'.$key.'")'; + } + } + // List of mass actions available + $arrayofmassactions = array( + //'presend'=>$langs->trans("SendByMail"), + //'builddoc'=>$langs->trans("PDFMerge"), + ); + if ($user->rights->produit->supprimer) $arrayofmassactions['delete']=$langs->trans("Delete"); + if ($massaction == 'presend' || $massaction == 'createbills') $arrayofmassactions=array(); + + // Filter on categories + $moreforfilter=''; + if (! empty($conf->categorie->enabled)) + { + $moreforfilter.='
'; + $moreforfilter.=$langs->trans('Categories'). ': '; + $moreforfilter.=$htmlother->select_categories(Categorie::TYPE_PRODUCT,$search_categ,'search_categ',1); + $moreforfilter.='
'; + } + + //Show/hide child products. Hidden by default + if (!empty($conf->variants->enabled) && $type === 0) { + $moreforfilter.='
'; + $moreforfilter.= ''; + $moreforfilter.= ' '; + $moreforfilter.='
'; + } + + if ($moreforfilter) + { + $parameters=array(); + $reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters); // Note that $action and $object may have been modified by hook + + if(!empty($hookmanager->resPrint)) { + $moreforfilter.=$hookmanager->resPrint; + } + + } + + $param=''; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); + if ($search_categ > 0) $param.="&search_categ=".urlencode($search_categ); + if ($sref) $param="&sref=".urlencode($sref); + if ($search_ref_supplier) $param="&search_ref_supplier=".urlencode($search_ref_supplier); + if ($sbarcode) $param.=($sbarcode?"&sbarcode=".urlencode($sbarcode):""); + if ($snom) $param.="&snom=".urlencode($snom); + if ($sall) $param.="&sall=".urlencode($sall); + if ($tosell != '') $param.="&tosell=".urlencode($tosell); + if ($tobuy != '') $param.="&tobuy=".urlencode($tobuy); + if ($fourn_id > 0) $param.=($fourn_id?"&fourn_id=".$fourn_id:""); + if ($seach_categ) $param.=($search_categ?"&search_categ=".urlencode($search_categ):""); + if ($type != '') $param.='&type='.urlencode($type); + if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss); + if ($search_tobatch) $param="&search_ref_supplier=".urlencode($search_ref_supplier); + if ($search_accountancy_code_sell) $param="&search_accountancy_code_sell=".urlencode($search_accountancy_code_sell); + if ($search_accountancy_code_buy) $param="&search_accountancy_code_buy=".urlencode($search_accountancy_code_buy); + // Add $param from extra fields + foreach ($search_array_options as $key => $val) + { + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val); + } + + //var_dump($arraytitle,$arrayhide); + $list=new Listview($db, 'products'); + $listHTML = $list->render($sql,array( + 'list'=>array( + 'title'=>$texte + ,'image'=>'title_products.png' + ,'massactions'=>$arrayofmassactions + ,'param_url'=>$param + ,'messageNothing'=>'' + ) + ,'limit'=>array( + 'nbLine'=>$limit + ) + ,'sortfield'=>$sortfield + ,'sortorder'=>$sortorder + ,'title'=>$arraytitle // column definition title (only defined where abble to show) + ,'position'=>array( + 'text-align'=>$arrayalign + ,'rank'=>$arrayposition + ) + ,'allow-fields-select'=>1 // allow to select hidden fields + ,'head_search'=>$moreforfilter //custom search on head + ,'no-auto-sql-search'=>1 //disabled auto completion sql for search and pager url, use dolibarr style for migration of product list + ,'translate'=>array() + ,'search'=>array( + 'ref'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'sref') + ,'label'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'snom') + ,'tosell'=>array('search_type'=> array('0'=>$langs->trans('ProductStatusNotOnSellShort'),'1'=>$langs->trans('ProductStatusOnSellShort')), 'fieldname'=>'tosell') + ,'tobuy'=>array('search_type'=> array('0'=>$langs->trans('ProductStatusNotOnBuyShort'),'1'=>$langs->trans('ProductStatusOnBuyShort')), 'fieldname'=>'tobuy') + ,'barcode'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'sbarcode') + ,'accountancy_code_sell'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'search_accountancy_code_sell') + ,'accountancy_code_buy'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'search_accountancy_code_buy') + ) + ,'type'=>array( + 'datec'=>'datetime' + ,'tms'=>'datetime' + ) + ,'hide'=>$arrayhide + ,'eval'=>$arrayeval + )); + + $num = $list->totalRow; + + $arrayofselected=is_array($toselect)?$toselect:array(); + + if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall) + { + $id = $list->TField[0]->rowid; + header("Location: ".DOL_URL_ROOT.'/product/card.php?id='.$id); + exit; + } + + $helpurl=''; + if (isset($type)) + { + if ($type == 0) + { + $helpurl='EN:Module_Products|FR:Module_Produits|ES:Módulo_Productos'; + } + else if ($type == 1) + { + $helpurl='EN:Module_Services_En|FR:Module_Services|ES:Módulo_Servicios'; + } + } + + llxHeader('',$title,$helpurl,''); + + // Displays product removal confirmation + if (GETPOST('delprod')) { + setEventMessages($langs->trans("ProductDeleted", GETPOST('delprod')), null, 'mesgs'); + } + + print '
'; + if ($optioncss != '') print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + echo $listHTML; + + print '
'; + +} + + +llxFooter(); +$db->close();