list.php 44 KB

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