list.php 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. <?php
  2. /* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
  5. * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
  6. * Copyright (C) 2013-2016 Juanjo Menent <jmenent@2byte.es>
  7. * Copyright (C) 2013-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  8. * Copyright (C) 2013 Jean Heimburger <jean@tiaris.info>
  9. * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
  10. * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
  11. * Copyright (C) 2013 Adolfo segura <adolfo.segura@gmail.com>
  12. * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  13. * Copyright (C) 2016 Ferran Marcet <fmarcet@2byte.es>
  14. *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 3 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. */
  28. /**
  29. * \file htdocs/product/list.php
  30. * \ingroup produit
  31. * \brief Page to list products and services
  32. */
  33. require '../main.inc.php';
  34. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
  35. require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
  36. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
  37. if (! empty($conf->categorie->enabled))
  38. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  39. $langs->load("products");
  40. $langs->load("stocks");
  41. $langs->load("suppliers");
  42. $langs->load("companies");
  43. if (! empty($conf->productbatch->enabled)) $langs->load("productbatch");
  44. $action=GETPOST('action','alpha');
  45. $massaction=GETPOST('massaction','alpha');
  46. $show_files=GETPOST('show_files','int');
  47. $confirm=GETPOST('confirm','alpha');
  48. $toselect = GETPOST('toselect', 'array');
  49. $sall=GETPOST('sall', 'alphanohtml');
  50. $sref=GETPOST("sref");
  51. $sbarcode=GETPOST("sbarcode");
  52. $snom=GETPOST("snom");
  53. $search_type = GETPOST("search_type",'int');
  54. $search_sale = GETPOST("search_sale");
  55. $search_categ = GETPOST("search_categ",'int');
  56. $tosell = GETPOST("tosell", 'int');
  57. $tobuy = GETPOST("tobuy", 'int');
  58. $fourn_id = GETPOST("fourn_id",'int');
  59. $catid = GETPOST('catid','int');
  60. $search_tobatch = GETPOST("search_tobatch",'int');
  61. $search_accountancy_code_sell = GETPOST("search_accountancy_code_sell",'alpha');
  62. $search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha');
  63. $optioncss = GETPOST('optioncss','alpha');
  64. $type=(int) GETPOST("type","int");
  65. //Show/hide child products. Hidden by default
  66. if (!$_POST) {
  67. $search_hidechildproducts = 'on';
  68. } else {
  69. $search_hidechildproducts = GETPOST('search_hidechildproducts');
  70. }
  71. $diroutputmassaction=$conf->product->dir_output . '/temp/massgeneration/'.$user->id;
  72. $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
  73. $sortfield = GETPOST("sortfield",'alpha');
  74. $sortorder = GETPOST("sortorder",'alpha');
  75. $page = (GETPOST("page",'int')?GETPOST("page", 'int'):0);
  76. if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1
  77. $offset = $limit * $page;
  78. $pageprev = $page - 1;
  79. $pagenext = $page + 1;
  80. if (! $sortfield) $sortfield="p.ref";
  81. if (! $sortorder) $sortorder="ASC";
  82. // Initialize context for list
  83. $contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'productservicelist';
  84. if ((string) $type == '1') { $contextpage='servicelist'; if ($search_type=='') $search_type='1'; }
  85. if ((string) $type == '0') { $contextpage='productlist'; if ($search_type=='') $search_type='0'; }
  86. // Initialize technical object to manage hooks. Note that conf->hooks_modules contains array of hooks
  87. $hookmanager->initHooks(array($contextpage));
  88. $extrafields = new ExtraFields($db);
  89. $form=new Form($db);
  90. // fetch optionals attributes and labels
  91. $extralabels = $extrafields->fetch_name_optionals_label('product');
  92. $search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_');
  93. if (empty($action)) $action='list';
  94. // Get object canvas (By default, this is not defined, so standard usage of dolibarr)
  95. $canvas=GETPOST("canvas");
  96. $objcanvas=null;
  97. if (! empty($canvas))
  98. {
  99. require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
  100. $objcanvas = new Canvas($db,$action);
  101. $objcanvas->getCanvas('product','list',$canvas);
  102. }
  103. // Security check
  104. if ($search_type=='0') $result=restrictedArea($user,'produit','','','','','',$objcanvas);
  105. else if ($search_type=='1') $result=restrictedArea($user,'service','','','','','',$objcanvas);
  106. else $result=restrictedArea($user,'produit|service','','','','','',$objcanvas);
  107. // Define virtualdiffersfromphysical
  108. $virtualdiffersfromphysical=0;
  109. if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER))
  110. {
  111. $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs.
  112. }
  113. // List of fields to search into when doing a "search in all"
  114. $fieldstosearchall = array(
  115. 'p.ref'=>"Ref",
  116. 'pfp.ref_fourn'=>"RefSupplier",
  117. 'p.label'=>"ProductLabel",
  118. 'p.description'=>"Description",
  119. "p.note"=>"Note",
  120. );
  121. // multilang
  122. if (! empty($conf->global->MAIN_MULTILANGS))
  123. {
  124. $fieldstosearchall['pl.label']='ProductLabelTranslated';
  125. $fieldstosearchall['pl.description']='ProductDescriptionTranslated';
  126. $fieldstosearchall['pl.note']='ProductNoteTranslated';
  127. }
  128. if (! empty($conf->barcode->enabled)) {
  129. $fieldstosearchall['p.barcode']='Gencod';
  130. }
  131. if (empty($conf->global->PRODUIT_MULTIPRICES))
  132. {
  133. $titlesellprice=$langs->trans("SellingPrice");
  134. if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES))
  135. {
  136. $titlesellprice=$form->textwithpicto($langs->trans("SellingPrice"), $langs->trans("DefaultPriceRealPriceMayDependOnCustomer"));
  137. }
  138. }
  139. // Definition of fields for lists
  140. $arrayfields=array(
  141. 'p.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1),
  142. //'pfp.ref_fourn'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))),
  143. 'p.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
  144. 'p.fk_product_type'=>array('label'=>$langs->trans("Type"), 'checked'=>0, 'enabled'=>(! empty($conf->produit->enabled) && ! empty($conf->service->enabled))),
  145. 'p.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>($contextpage != 'servicelist'), 'enabled'=>(! empty($conf->barcode->enabled))),
  146. 'p.duration'=>array('label'=>$langs->trans("Duration"), 'checked'=>($contextpage != 'productlist'), 'enabled'=>(! empty($conf->service->enabled))),
  147. 'p.sellprice'=>array('label'=>$langs->trans("SellingPrice"), 'checked'=>1, 'enabled'=>empty($conf->global->PRODUIT_MULTIPRICES)),
  148. 'p.minbuyprice'=>array('label'=>$langs->trans("BuyingPriceMinShort"), 'checked'=>1, 'enabled'=>(! empty($user->rights->fournisseur->lire))),
  149. 'p.seuil_stock_alerte'=>array('label'=>$langs->trans("StockLimit"), 'checked'=>0, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')),
  150. 'p.desiredstock'=>array('label'=>$langs->trans("DesiredStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')),
  151. 'p.stock'=>array('label'=>$langs->trans("PhysicalStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')),
  152. 'stock_virtual'=>array('label'=>$langs->trans("VirtualStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service' && $virtualdiffersfromphysical)),
  153. 'p.tobatch'=>array('label'=>$langs->trans("ManageLotSerial"), 'checked'=>0, 'enabled'=>(! empty($conf->productbatch->enabled))),
  154. 'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0),
  155. 'p.accountancy_code_buy'=>array('label'=>$langs->trans("ProductAccountancyBuyCode"), 'checked'=>0),
  156. 'p.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
  157. 'p.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500),
  158. 'p.tosell'=>array('label'=>$langs->trans("Status").' ('.$langs->trans("Sell").')', 'checked'=>1, 'position'=>1000),
  159. 'p.tobuy'=>array('label'=>$langs->trans("Status").' ('.$langs->trans("Buy").')', 'checked'=>1, 'position'=>1000)
  160. );
  161. // Extra fields
  162. if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
  163. {
  164. foreach($extrafields->attribute_label as $key => $val)
  165. {
  166. $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key]);
  167. }
  168. }
  169. /*
  170. * Actions
  171. */
  172. if (GETPOST('cancel')) { $action='list'; $massaction=''; }
  173. if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; }
  174. $parameters=array();
  175. $reshook=$hookmanager->executeHooks('doActions',$parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
  176. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  177. if (empty($reshook))
  178. {
  179. // Selection of new fields
  180. include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
  181. // Purge search criteria
  182. if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
  183. {
  184. $sall="";
  185. $sref="";
  186. $snom="";
  187. $sbarcode="";
  188. $search_categ=0;
  189. $tosell="";
  190. $tobuy="";
  191. $search_tobatch='';
  192. $search_type='';
  193. $search_accountancy_code_sell='';
  194. $search_accountancy_code_buy='';
  195. $search_array_options=array();
  196. }
  197. // Mass actions
  198. $objectclass='Product';
  199. if ((string) $search_type == '1') { $objectlabel='Services'; }
  200. if ((string) $search_type == '0') { $objectlabel='Products'; }
  201. $permtoread = $user->rights->produit->lire;
  202. $permtodelete = $user->rights->produit->supprimer;
  203. $uploaddir = $conf->product->dir_output;
  204. include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
  205. }
  206. /*
  207. * View
  208. */
  209. $htmlother=new FormOther($db);
  210. if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
  211. {
  212. $objcanvas->assign_values($action); // This must contains code to load data (must call LoadListDatas($limit, $offset, $sortfield, $sortorder))
  213. $objcanvas->display_canvas($action); // This is code to show template
  214. }
  215. else
  216. {
  217. $title=$langs->trans("ProductsAndServices");
  218. if ($search_type != '' && $search_type != '-1')
  219. {
  220. if ($search_type==1)
  221. {
  222. $texte = $langs->trans("Services");
  223. }
  224. else
  225. {
  226. $texte = $langs->trans("Products");
  227. }
  228. }
  229. else
  230. {
  231. $texte = $langs->trans("ProductsAndServices");
  232. }
  233. $sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.fk_product_type, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
  234. $sql.= ' p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
  235. $sql.= ' p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy,';
  236. $sql.= ' p.datec as date_creation, p.tms as date_update,';
  237. //$sql.= ' pfp.ref_fourn as ref_supplier, ';
  238. $sql.= ' MIN(pfp.unitprice) as minsellprice';
  239. if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
  240. $sql .= ', pac.rowid prod_comb_id';
  241. }
  242. // Add fields from extrafields
  243. foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : '');
  244. // Add fields from hooks
  245. $parameters=array();
  246. $reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters); // Note that $action and $object may have been modified by hook
  247. $sql.=$hookmanager->resPrint;
  248. $sql.= ' FROM '.MAIN_DB_PREFIX.'product as p';
  249. 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)";
  250. 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
  251. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
  252. // multilang
  253. 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() ."'";
  254. if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
  255. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
  256. }
  257. $sql.= ' WHERE p.entity IN ('.getEntity('product').')';
  258. if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall);
  259. // if the type is not 1, we show all products (type = 0,2,3)
  260. if (dol_strlen($search_type) && $search_type != '-1')
  261. {
  262. if ($search_type == 1) $sql.= " AND p.fk_product_type = 1";
  263. else $sql.= " AND p.fk_product_type <> 1";
  264. }
  265. if ($sref) $sql .= natural_search('p.ref', $sref);
  266. if ($snom) $sql .= natural_search('p.label', $snom);
  267. if ($sbarcode) $sql .= natural_search('p.barcode', $sbarcode);
  268. if (isset($tosell) && dol_strlen($tosell) > 0 && $tosell!=-1) $sql.= " AND p.tosell = ".$db->escape($tosell);
  269. if (isset($tobuy) && dol_strlen($tobuy) > 0 && $tobuy!=-1) $sql.= " AND p.tobuy = ".$db->escape($tobuy);
  270. if (dol_strlen($canvas) > 0) $sql.= " AND p.canvas = '".$db->escape($canvas)."'";
  271. if ($catid > 0) $sql.= " AND cp.fk_categorie = ".$catid;
  272. if ($catid == -2) $sql.= " AND cp.fk_categorie IS NULL";
  273. if ($search_categ > 0) $sql.= " AND cp.fk_categorie = ".$db->escape($search_categ);
  274. if ($search_categ == -2) $sql.= " AND cp.fk_categorie IS NULL";
  275. if ($fourn_id > 0) $sql.= " AND pfp.fk_soc = ".$fourn_id;
  276. if ($search_tobatch != '' && $search_tobatch >= 0) $sql.= " AND p.tobatch = ".$db->escape($search_tobatch);
  277. if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell);
  278. if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy);
  279. // Add where from extra fields
  280. if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
  281. $sql .= " AND pac.rowid IS NULL";
  282. }
  283. // Add where from extra fields
  284. foreach ($search_array_options as $key => $val)
  285. {
  286. $crit=$val;
  287. $tmpkey=preg_replace('/search_options_/','',$key);
  288. $typ=$extrafields->attribute_type[$tmpkey];
  289. $mode=0;
  290. if (in_array($typ, array('int','double'))) $mode=1; // Search on a numeric
  291. if ($val && ( ($crit != '' && ! in_array($typ, array('select'))) || ! empty($crit)))
  292. {
  293. $sql .= natural_search('ef.'.$tmpkey, $crit, $mode);
  294. }
  295. }
  296. // Add where from hooks
  297. $parameters=array();
  298. $reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters); // Note that $action and $object may have been modified by hook
  299. $sql.=$hookmanager->resPrint;
  300. $sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
  301. $sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
  302. $sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy';
  303. if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
  304. $sql .= ', pac.rowid';
  305. }
  306. // Add fields from extrafields
  307. foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key : '');
  308. // Add fields from hooks
  309. $parameters=array();
  310. $reshook=$hookmanager->executeHooks('printFieldSelect',$parameters); // Note that $action and $object may have been modified by hook
  311. $sql.=$hookmanager->resPrint;
  312. //if (GETPOST("toolowstock")) $sql.= " HAVING SUM(s.reel) < p.seuil_stock_alerte"; // Not used yet
  313. $sql.= $db->order($sortfield,$sortorder);
  314. $nbtotalofrecords = '';
  315. if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
  316. {
  317. $result = $db->query($sql);
  318. $nbtotalofrecords = $db->num_rows($result);
  319. }
  320. $sql.= $db->plimit($limit + 1, $offset);
  321. $resql = $db->query($sql);
  322. if ($resql)
  323. {
  324. $num = $db->num_rows($resql);
  325. $arrayofselected=is_array($toselect)?$toselect:array();
  326. if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall)
  327. {
  328. $obj = $db->fetch_object($resql);
  329. $id = $obj->rowid;
  330. header("Location: ".DOL_URL_ROOT.'/product/card.php?id='.$id);
  331. exit;
  332. }
  333. $helpurl='';
  334. if ($search_type != '')
  335. {
  336. if ($search_type == 0)
  337. {
  338. $helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
  339. }
  340. else if ($search_type == 1)
  341. {
  342. $helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
  343. }
  344. }
  345. llxHeader('',$title,$helpurl,'');
  346. // Displays product removal confirmation
  347. if (GETPOST('delprod')) {
  348. setEventMessages($langs->trans("ProductDeleted", GETPOST('delprod')), null, 'mesgs');
  349. }
  350. $param='';
  351. if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
  352. if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
  353. if ($search_categ > 0) $param.="&amp;search_categ=".urlencode($search_categ);
  354. if ($sref) $param="&amp;sref=".urlencode($sref);
  355. if ($search_ref_supplier) $param="&amp;search_ref_supplier=".urlencode($search_ref_supplier);
  356. if ($sbarcode) $param.=($sbarcode?"&amp;sbarcode=".urlencode($sbarcode):"");
  357. if ($snom) $param.="&amp;snom=".urlencode($snom);
  358. if ($sall) $param.="&amp;sall=".urlencode($sall);
  359. if ($tosell != '') $param.="&amp;tosell=".urlencode($tosell);
  360. if ($tobuy != '') $param.="&amp;tobuy=".urlencode($tobuy);
  361. if ($fourn_id > 0) $param.=($fourn_id?"&amp;fourn_id=".$fourn_id:"");
  362. if ($seach_categ) $param.=($search_categ?"&amp;search_categ=".urlencode($search_categ):"");
  363. if ($type != '') $param.='&amp;type='.urlencode($type);
  364. if ($search_type != '') $param.='&amp;search_type='.urlencode($search_type);
  365. if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
  366. if ($search_tobatch) $param="&amp;search_ref_supplier=".urlencode($search_ref_supplier);
  367. if ($search_accountancy_code_sell) $param="&amp;search_accountancy_code_sell=".urlencode($search_accountancy_code_sell);
  368. if ($search_accountancy_code_buy) $param="&amp;search_accountancy_code_buy=".urlencode($search_accountancy_code_buy);
  369. // Add $param from extra fields
  370. foreach ($search_array_options as $key => $val)
  371. {
  372. $crit=$val;
  373. $tmpkey=preg_replace('/search_options_/','',$key);
  374. if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val);
  375. }
  376. // List of mass actions available
  377. $arrayofmassactions = array(
  378. //'presend'=>$langs->trans("SendByMail"),
  379. //'builddoc'=>$langs->trans("PDFMerge"),
  380. );
  381. if ($user->rights->produit->supprimer) $arrayofmassactions['delete']=$langs->trans("Delete");
  382. if ($massaction == 'presend' || $massaction == 'createbills') $arrayofmassactions=array();
  383. $massactionbutton=$form->selectMassAction('', $arrayofmassactions);
  384. print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">';
  385. if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
  386. print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  387. print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
  388. print '<input type="hidden" name="action" value="list">';
  389. print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
  390. print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
  391. print '<input type="hidden" name="page" value="'.$page.'">';
  392. print '<input type="hidden" name="type" value="'.$type.'">';
  393. if (empty($arrayfields['p.fk_product_type']['checked'])) print '<input type="hidden" name="search_type" value="'.dol_escape_htmltag($search_type).'">';
  394. print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_products.png', 0, '', '', $limit);
  395. if (! empty($catid))
  396. {
  397. print "<div id='ways'>";
  398. $c = new Categorie($db);
  399. $ways = $c->print_all_ways(' &gt; ','product/list.php');
  400. print " &gt; ".$ways[0]."<br>\n";
  401. print "</div><br>";
  402. }
  403. if (! empty($canvas) && file_exists(DOL_DOCUMENT_ROOT.'/product/canvas/'.$canvas.'/actions_card_'.$canvas.'.class.php'))
  404. {
  405. $fieldlist = $object->field_list;
  406. $datas = $object->list_datas;
  407. $picto='title.png';
  408. $title_picto = img_picto('',$picto);
  409. $title_text = $title;
  410. // Default templates directory
  411. $template_dir = DOL_DOCUMENT_ROOT . '/product/canvas/'.$canvas.'/tpl/';
  412. // Check if a custom template is present
  413. if (file_exists(DOL_DOCUMENT_ROOT . '/theme/'.$conf->theme.'/tpl/product/'.$canvas.'/list.tpl.php'))
  414. {
  415. $template_dir = DOL_DOCUMENT_ROOT . '/theme/'.$conf->theme.'/tpl/product/'.$canvas.'/';
  416. }
  417. include $template_dir.'list.tpl.php'; // Include native PHP templates
  418. }
  419. else
  420. {
  421. if ($sall)
  422. {
  423. foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
  424. print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall);
  425. }
  426. // Filter on categories
  427. $moreforfilter='';
  428. if (! empty($conf->categorie->enabled))
  429. {
  430. $moreforfilter.='<div class="divsearchfield">';
  431. $moreforfilter.=$langs->trans('Categories'). ': ';
  432. $moreforfilter.=$htmlother->select_categories(Categorie::TYPE_PRODUCT,$search_categ,'search_categ',1);
  433. $moreforfilter.='</div>';
  434. }
  435. //Show/hide child products. Hidden by default
  436. if (!empty($conf->variants->enabled) && $search_type === 0) {
  437. $moreforfilter.='<div class="divsearchfield">';
  438. $moreforfilter.= '<input type="checkbox" id="search_hidechildproducts" name="search_hidechildproducts" value="on"'.($search_hidechildproducts ? 'checked="checked"' : '').'>';
  439. $moreforfilter.= ' <label for="search_hidechildproducts">'.$langs->trans('HideChildProducts').'</label>';
  440. $moreforfilter.='</div>';
  441. }
  442. if ($moreforfilter)
  443. {
  444. print '<div class="liste_titre liste_titre_bydiv centpercent">';
  445. print $moreforfilter;
  446. $parameters=array();
  447. $reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters); // Note that $action and $object may have been modified by hook
  448. print $hookmanager->resPrint;
  449. print '</div>';
  450. }
  451. $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
  452. $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
  453. if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1);
  454. print '<div class="div-table-responsive">';
  455. print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
  456. // Lines with input filters
  457. print '<tr class="liste_titre_filter">';
  458. if (! empty($arrayfields['p.ref']['checked']))
  459. {
  460. print '<td class="liste_titre" align="left">';
  461. print '<input class="flat" type="text" name="sref" size="8" value="'.dol_escape_htmltag($sref).'">';
  462. print '</td>';
  463. }
  464. if (! empty($arrayfields['pfp.ref_fourn']['checked']))
  465. {
  466. print '<td class="liste_titre" align="left">';
  467. print '<input class="flat" type="text" name="search_ref_supplier" size="8" value="'.dol_escape_htmltag($search_ref_supplier).'">';
  468. print '</td>';
  469. }
  470. if (! empty($arrayfields['p.label']['checked']))
  471. {
  472. print '<td class="liste_titre" align="left">';
  473. print '<input class="flat" type="text" name="snom" size="12" value="'.dol_escape_htmltag($snom).'">';
  474. print '</td>';
  475. }
  476. // Type
  477. if (! empty($arrayfields['p.fk_product_type']['checked']))
  478. {
  479. print '<td class="liste_titre" align="left">';
  480. $array=array('-1'=>'&nbsp;', '0'=>$langs->trans('Product'), '1'=>$langs->trans('Service'));
  481. print $form->selectarray('search_type', $array, $search_type);
  482. print '</td>';
  483. }
  484. // Barcode
  485. if (! empty($arrayfields['p.barcode']['checked']))
  486. {
  487. print '<td class="liste_titre">';
  488. print '<input class="flat" type="text" name="sbarcode" size="6" value="'.dol_escape_htmltag($sbarcode).'">';
  489. print '</td>';
  490. }
  491. // Duration
  492. if (! empty($arrayfields['p.duration']['checked']))
  493. {
  494. print '<td class="liste_titre">';
  495. print '&nbsp;';
  496. print '</td>';
  497. }
  498. // Sell price
  499. if (! empty($arrayfields['p.sellprice']['checked']))
  500. {
  501. print '<td class="liste_titre" align="right">';
  502. print '</td>';
  503. }
  504. // Minimum buying Price
  505. if (! empty($arrayfields['p.minbuyprice']['checked']))
  506. {
  507. print '<td class="liste_titre">';
  508. print '&nbsp;';
  509. print '</td>';
  510. }
  511. // Limit for alert
  512. if (! empty($arrayfields['p.seuil_stock_alerte']['checked']))
  513. {
  514. print '<td class="liste_titre">';
  515. print '&nbsp;';
  516. print '</td>';
  517. }
  518. // Desired stock
  519. if (! empty($arrayfields['p.desiredstock']['checked']))
  520. {
  521. print '<td class="liste_titre">';
  522. print '&nbsp;';
  523. print '</td>';
  524. }
  525. // Stock
  526. if (! empty($arrayfields['p.stock']['checked'])) print '<td class="liste_titre">&nbsp;</td>';
  527. // Stock
  528. if (! empty($arrayfields['stock_virtual']['checked'])) print '<td class="liste_titre">&nbsp;</td>';
  529. // To batch
  530. if (! empty($arrayfields['p.tobatch']['checked'])) print '<td class="liste_titre center">'.$form->selectyesno($search_tobatch, '', '', '', 1).'</td>';
  531. // Accountancy code sell
  532. if (! empty($arrayfields['p.accountancy_code_sell']['checked'])) print '<td class="liste_titre"><input class="flat" type="text" name="search_accountancy_code_sell" size="6" value="'.dol_escape_htmltag($search_accountancy_code_sell).'"></td>';
  533. // Accountancy code sell
  534. if (! empty($arrayfields['p.accountancy_code_buy']['checked'])) print '<td class="liste_titre"><input class="flat" type="text" name="search_accountancy_code_buy" size="6" value="'.dol_escape_htmltag($search_accountancy_code_buy).'"></td>';
  535. // Extra fields
  536. if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
  537. {
  538. foreach($extrafields->attribute_label as $key => $val)
  539. {
  540. if (! empty($arrayfields["ef.".$key]['checked'])) print '<td class="liste_titre"></td>';
  541. }
  542. }
  543. // Fields from hook
  544. $parameters=array('arrayfields'=>$arrayfields);
  545. $reshook=$hookmanager->executeHooks('printFieldListOption',$parameters); // Note that $action and $object may have been modified by hook
  546. print $hookmanager->resPrint;
  547. // Date creation
  548. if (! empty($arrayfields['p.datec']['checked']))
  549. {
  550. print '<td class="liste_titre">';
  551. print '</td>';
  552. }
  553. // Date modification
  554. if (! empty($arrayfields['p.tms']['checked']))
  555. {
  556. print '<td class="liste_titre">';
  557. print '</td>';
  558. }
  559. if (! empty($arrayfields['p.tosell']['checked']))
  560. {
  561. print '<td class="liste_titre" align="right">';
  562. print $form->selectarray('tosell', array('0'=>$langs->trans('ProductStatusNotOnSellShort'),'1'=>$langs->trans('ProductStatusOnSellShort')),$tosell,1);
  563. print '</td >';
  564. }
  565. if (! empty($arrayfields['p.tobuy']['checked']))
  566. {
  567. print '<td class="liste_titre" align="right">';
  568. print $form->selectarray('tobuy', array('0'=>$langs->trans('ProductStatusNotOnBuyShort'),'1'=>$langs->trans('ProductStatusOnBuyShort')),$tobuy,1);
  569. print '</td>';
  570. }
  571. print '<td class="liste_titre" align="middle">';
  572. $searchpicto=$form->showFilterButtons();
  573. print $searchpicto;
  574. print '</td>';
  575. print '</tr>';
  576. print '<tr class="liste_titre">';
  577. if (! empty($arrayfields['p.ref']['checked'])) print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"],"p.ref","",$param,"",$sortfield,$sortorder);
  578. if (! empty($arrayfields['pfp.ref_fourn']['checked'])) print_liste_field_titre($arrayfields['pfp.ref_fourn']['label'], $_SERVER["PHP_SELF"],"pfp.ref_fourn","",$param,"",$sortfield,$sortorder);
  579. if (! empty($arrayfields['p.label']['checked'])) print_liste_field_titre($arrayfields['p.label']['label'], $_SERVER["PHP_SELF"],"p.label","",$param,"",$sortfield,$sortorder);
  580. if (! empty($arrayfields['p.fk_product_type']['checked'])) print_liste_field_titre($arrayfields['p.fk_product_type']['label'], $_SERVER["PHP_SELF"],"p.fk_product_type","",$param,"",$sortfield,$sortorder);
  581. if (! empty($arrayfields['p.barcode']['checked'])) print_liste_field_titre($arrayfields['p.barcode']['label'], $_SERVER["PHP_SELF"],"p.barcode","",$param,"",$sortfield,$sortorder);
  582. if (! empty($arrayfields['p.duration']['checked'])) print_liste_field_titre($arrayfields['p.duration']['label'], $_SERVER["PHP_SELF"],"p.duration","",$param,'align="center"',$sortfield,$sortorder);
  583. if (! empty($arrayfields['p.sellprice']['checked'])) print_liste_field_titre($arrayfields['p.sellprice']['label'], $_SERVER["PHP_SELF"],"","",$param,'align="right"',$sortfield,$sortorder);
  584. if (! empty($arrayfields['p.minbuyprice']['checked'])) print_liste_field_titre($arrayfields['p.minbuyprice']['label'], $_SERVER["PHP_SELF"],"","",$param,'align="right"',$sortfield,$sortorder);
  585. if (! empty($arrayfields['p.seuil_stock_alerte']['checked'])) print_liste_field_titre($arrayfields['p.seuil_stock_alerte']['label'], $_SERVER["PHP_SELF"],"p.seuil_stock_alerte","",$param,'align="right"',$sortfield,$sortorder);
  586. if (! empty($arrayfields['p.desiredstock']['checked'])) print_liste_field_titre($arrayfields['p.desiredstock']['label'], $_SERVER["PHP_SELF"],"p.desiredstock","",$param,'align="right"',$sortfield,$sortorder);
  587. if (! empty($arrayfields['p.stock']['checked'])) print_liste_field_titre($arrayfields['p.stock']['label'], $_SERVER["PHP_SELF"],"p.stock","",$param,'align="right"',$sortfield,$sortorder);
  588. if (! empty($arrayfields['stock_virtual']['checked'])) print_liste_field_titre($arrayfields['stock_virtual']['label'], $_SERVER["PHP_SELF"],"","",$param,'align="right"',$sortfield,$sortorder);
  589. if (! empty($arrayfields['p.tobatch']['checked'])) print_liste_field_titre($arrayfields['p.tobatch']['label'], $_SERVER["PHP_SELF"],"p.tobatch","",$param,'align="center"',$sortfield,$sortorder);
  590. if (! empty($arrayfields['p.accountancy_code_sell']['checked'])) print_liste_field_titre($arrayfields['p.accountancy_code_sell']['label'], $_SERVER["PHP_SELF"],"p.accountancy_code_sell","",$param,'',$sortfield,$sortorder);
  591. if (! empty($arrayfields['p.accountancy_code_buy']['checked'])) print_liste_field_titre($arrayfields['p.accountancy_code_buy']['label'], $_SERVER["PHP_SELF"],"p.accountancy_code_buy","",$param,'',$sortfield,$sortorder);
  592. if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
  593. {
  594. foreach($extrafields->attribute_label as $key => $val)
  595. {
  596. if (! empty($arrayfields["ef.".$key]['checked']))
  597. {
  598. $align=$extrafields->getAlignFlag($key);
  599. print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
  600. }
  601. }
  602. }
  603. // Hook fields
  604. $parameters=array('arrayfields'=>$arrayfields);
  605. $reshook=$hookmanager->executeHooks('printFieldListTitle',$parameters); // Note that $action and $object may have been modified by hook
  606. print $hookmanager->resPrint;
  607. if (! empty($arrayfields['p.datec']['checked'])) print_liste_field_titre($arrayfields['p.datec']['label'],$_SERVER["PHP_SELF"],"p.datec","",$param,'align="center" class="nowrap"',$sortfield,$sortorder);
  608. if (! empty($arrayfields['p.tms']['checked'])) print_liste_field_titre($arrayfields['p.tms']['label'],$_SERVER["PHP_SELF"],"p.tms","",$param,'align="center" class="nowrap"',$sortfield,$sortorder);
  609. if (! empty($arrayfields['p.tosell']['checked'])) print_liste_field_titre($arrayfields['p.tosell']['label'],$_SERVER["PHP_SELF"],"p.tosell","",$param,'align="right"',$sortfield,$sortorder);
  610. if (! empty($arrayfields['p.tobuy']['checked'])) print_liste_field_titre($arrayfields['p.tobuy']['label'],$_SERVER["PHP_SELF"],"p.tobuy","",$param,'align="right"',$sortfield,$sortorder);
  611. print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch ');
  612. print "</tr>\n";
  613. $product_static=new Product($db);
  614. $product_fourn =new ProductFournisseur($db);
  615. $i = 0;
  616. $totalarray=array();
  617. while ($i < min($num,$limit))
  618. {
  619. $obj = $db->fetch_object($resql);
  620. // Multilangs
  621. if (! empty($conf->global->MAIN_MULTILANGS)) // si l'option est active
  622. {
  623. $sql = "SELECT label";
  624. $sql.= " FROM ".MAIN_DB_PREFIX."product_lang";
  625. $sql.= " WHERE fk_product=".$obj->rowid;
  626. $sql.= " AND lang='". $langs->getDefaultLang() ."'";
  627. $sql.= " LIMIT 1";
  628. $result = $db->query($sql);
  629. if ($result)
  630. {
  631. $objtp = $db->fetch_object($result);
  632. if (! empty($objtp->label)) $obj->label = $objtp->label;
  633. }
  634. }
  635. $product_static->id = $obj->rowid;
  636. $product_static->ref = $obj->ref;
  637. $product_static->ref_fourn = $obj->ref_supplier;
  638. $product_static->label = $obj->label;
  639. $product_static->type = $obj->fk_product_type;
  640. $product_static->status_buy = $obj->tobuy;
  641. $product_static->status = $obj->tosell;
  642. $product_static->entity = $obj->entity;
  643. if (! empty($conf->stock->enabled) && $user->rights->stock->lire && $search_type != 1) // To optimize call of load_stock
  644. {
  645. if ($obj->fk_product_type != 1) // Not a service
  646. {
  647. $product_static->load_stock('nobatch'); // Load stock_reel + stock_warehouse. This also call load_virtual_stock()
  648. }
  649. }
  650. print '<tr class="oddeven">';
  651. // Ref
  652. if (! empty($arrayfields['p.ref']['checked']))
  653. {
  654. print '<td class="nowrap">';
  655. print $product_static->getNomUrl(1,'',24);
  656. print "</td>\n";
  657. if (! $i) $totalarray['nbfield']++;
  658. }
  659. // Ref supplier
  660. if (! empty($arrayfields['pfp.ref_fourn']['checked']))
  661. {
  662. print '<td class="nowrap">';
  663. print $product_static->getNomUrl(1,'',24);
  664. print "</td>\n";
  665. if (! $i) $totalarray['nbfield']++;
  666. }
  667. // Label
  668. if (! empty($arrayfields['p.label']['checked']))
  669. {
  670. print '<td>'.dol_trunc($obj->label,40).'</td>';
  671. if (! $i) $totalarray['nbfield']++;
  672. }
  673. // Type
  674. if (! empty($arrayfields['p.fk_product_type']['checked']))
  675. {
  676. print '<td>'.$obj->fk_product_type.'</td>';
  677. if (! $i) $totalarray['nbfield']++;
  678. }
  679. // Barcode
  680. if (! empty($arrayfields['p.barcode']['checked']))
  681. {
  682. print '<td>'.$obj->barcode.'</td>';
  683. if (! $i) $totalarray['nbfield']++;
  684. }
  685. // Duration
  686. if (! empty($arrayfields['p.duration']['checked']))
  687. {
  688. print '<td align="center">';
  689. if (preg_match('/([0-9]+)[a-z]/i',$obj->duration))
  690. {
  691. if (preg_match('/([0-9]+)y/i',$obj->duration,$regs)) print $regs[1].' '.$langs->trans("DurationYear");
  692. elseif (preg_match('/([0-9]+)m/i',$obj->duration,$regs)) print $regs[1].' '.$langs->trans("DurationMonth");
  693. elseif (preg_match('/([0-9]+)w/i',$obj->duration,$regs)) print $regs[1].' '.$langs->trans("DurationWeek");
  694. elseif (preg_match('/([0-9]+)d/i',$obj->duration,$regs)) print $regs[1].' '.$langs->trans("DurationDay");
  695. //elseif (preg_match('/([0-9]+)h/i',$obj->duration,$regs)) print $regs[1].' '.$langs->trans("DurationHour");
  696. else print $obj->duration;
  697. }
  698. print '</td>';
  699. if (! $i) $totalarray['nbfield']++;
  700. }
  701. // Sell price
  702. if (! empty($arrayfields['p.sellprice']['checked']))
  703. {
  704. print '<td align="right">';
  705. if ($obj->tosell)
  706. {
  707. if ($obj->price_base_type == 'TTC') print price($obj->price_ttc).' '.$langs->trans("TTC");
  708. else print price($obj->price).' '.$langs->trans("HT");
  709. }
  710. print '</td>';
  711. if (! $i) $totalarray['nbfield']++;
  712. }
  713. // Better buy price
  714. if (! empty($arrayfields['p.minbuyprice']['checked']))
  715. {
  716. print '<td align="right">';
  717. if ($obj->tobuy && $obj->minsellprice != '')
  718. {
  719. //print price($obj->minsellprice).' '.$langs->trans("HT");
  720. if ($product_fourn->find_min_price_product_fournisseur($obj->rowid) > 0)
  721. {
  722. if ($product_fourn->product_fourn_price_id > 0)
  723. {
  724. if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire)
  725. {
  726. $htmltext=$product_fourn->display_price_product_fournisseur(1, 1, 0, 1);
  727. print $form->textwithpicto(price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"),$htmltext);
  728. }
  729. else print price($product_fourn->fourn_unitprice).' '.$langs->trans("HT");
  730. }
  731. }
  732. }
  733. print '</td>';
  734. if (! $i) $totalarray['nbfield']++;
  735. }
  736. // Limit alert
  737. if (! empty($arrayfields['p.seuil_stock_alerte']['checked']))
  738. {
  739. print '<td align="right">';
  740. if ($obj->fk_product_type != 1)
  741. {
  742. print $obj->seuil_stock_alerte;
  743. }
  744. print '</td>';
  745. if (! $i) $totalarray['nbfield']++;
  746. }
  747. // Desired stock
  748. if (! empty($arrayfields['p.desiredstock']['checked']))
  749. {
  750. print '<td align="right">';
  751. if ($obj->fk_product_type != 1)
  752. {
  753. print $obj->desiredstock;
  754. }
  755. print '</td>';
  756. if (! $i) $totalarray['nbfield']++;
  757. }
  758. // Stock
  759. if (! empty($arrayfields['p.stock']['checked']))
  760. {
  761. print '<td align="right">';
  762. if ($obj->fk_product_type != 1)
  763. {
  764. if ($obj->seuil_stock_alerte != '' && $product_static->stock_reel < (float) $obj->seuil_stock_alerte) print img_warning($langs->trans("StockLowerThanLimit", $obj->seuil_stock_alerte)).' ';
  765. print $product_static->stock_reel;
  766. }
  767. print '</td>';
  768. if (! $i) $totalarray['nbfield']++;
  769. }
  770. // Stock
  771. if (! empty($arrayfields['stock_virtual']['checked']))
  772. {
  773. print '<td align="right">';
  774. if ($obj->fk_product_type != 1)
  775. {
  776. if ($obj->seuil_stock_alerte != '' && $product_static->stock_theorique < (float) $obj->seuil_stock_alerte) print img_warning($langs->trans("StockLowerThanLimit", $obj->seuil_stock_alerte)).' ';
  777. print $product_static->stock_theorique;
  778. }
  779. print '</td>';
  780. if (! $i) $totalarray['nbfield']++;
  781. }
  782. // Lot/Serial
  783. if (! empty($arrayfields['p.tobatch']['checked']))
  784. {
  785. print '<td align="center">';
  786. print yn($obj->tobatch);
  787. print '</td>';
  788. if (! $i) $totalarray['nbfield']++;
  789. }
  790. // Accountancy code sell
  791. if (! empty($arrayfields['p.accountancy_code_sell']['checked']))
  792. {
  793. print '<td>'.$obj->accountancy_code_sell.'</td>';
  794. if (! $i) $totalarray['nbfield']++;
  795. }
  796. // Accountancy code sell
  797. if (! empty($arrayfields['p.accountancy_code_buy']['checked']))
  798. {
  799. print '<td>'.$obj->accountancy_code_buy.'</td>';
  800. if (! $i) $totalarray['nbfield']++;
  801. }
  802. // Extra fields
  803. if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
  804. {
  805. foreach($extrafields->attribute_label as $key => $val)
  806. {
  807. if (! empty($arrayfields["ef.".$key]['checked']))
  808. {
  809. print '<td';
  810. $align=$extrafields->getAlignFlag($key);
  811. if ($align) print ' align="'.$align.'"';
  812. print '>';
  813. $tmpkey='options_'.$key;
  814. print $extrafields->showOutputField($key, $obj->$tmpkey, '', 1);
  815. print '</td>';
  816. if (! $i) $totalarray['nbfield']++;
  817. }
  818. }
  819. }
  820. // Fields from hook
  821. $parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj);
  822. $reshook=$hookmanager->executeHooks('printFieldListValue',$parameters); // Note that $action and $object may have been modified by hook
  823. print $hookmanager->resPrint;
  824. // Date creation
  825. if (! empty($arrayfields['p.datec']['checked']))
  826. {
  827. print '<td align="center">';
  828. print dol_print_date($obj->date_creation, 'dayhour');
  829. print '</td>';
  830. if (! $i) $totalarray['nbfield']++;
  831. }
  832. // Date modification
  833. if (! empty($arrayfields['p.tms']['checked']))
  834. {
  835. print '<td align="center">';
  836. print dol_print_date($obj->date_update, 'dayhour');
  837. print '</td>';
  838. if (! $i) $totalarray['nbfield']++;
  839. }
  840. // Status (to sell)
  841. if (! empty($arrayfields['p.tosell']['checked']))
  842. {
  843. print '<td align="right" nowrap="nowrap">';
  844. if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
  845. print ajax_object_onoff($product_static, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
  846. } else {
  847. print $product_static->LibStatut($obj->tosell,5,0);
  848. }
  849. print '</td>';
  850. if (! $i) $totalarray['nbfield']++;
  851. }
  852. // Status (to buy)
  853. if (! empty($arrayfields['p.tobuy']['checked']))
  854. {
  855. print '<td align="right" nowrap="nowrap">';
  856. if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
  857. print ajax_object_onoff($product_static, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
  858. } else {
  859. print $product_static->LibStatut($obj->tobuy,5,1);
  860. }
  861. print '</td>';
  862. if (! $i) $totalarray['nbfield']++;
  863. }
  864. // Action
  865. print '<td class="nowrap" align="center">';
  866. if ($massactionbutton || $massaction) // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
  867. {
  868. $selected=0;
  869. if (in_array($obj->rowid, $arrayofselected)) $selected=1;
  870. print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected?' checked="checked"':'').'>';
  871. }
  872. print '</td>';
  873. if (! $i) $totalarray['nbfield']++;
  874. print "</tr>\n";
  875. $i++;
  876. }
  877. $db->free($resql);
  878. print "</table>";
  879. print "</div>";
  880. }
  881. print '</form>';
  882. }
  883. else
  884. {
  885. dol_print_error($db);
  886. }
  887. }
  888. llxFooter();
  889. $db->close();