dolibarr  20.0.0-beta
movement_list.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2015 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
7  * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
8  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <https://www.gnu.org/licenses/>.
22  */
23 
30 // Load Dolibarr environment
31 require '../../main.inc.php';
32 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php';
40 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
41 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
42 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
43 if (isModEnabled('project')) {
44  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
45  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
46 }
47 
48 // Load translation files required by the page
49 $langs->loadLangs(array('products', 'stocks', 'orders'));
50 if (isModEnabled('productbatch')) {
51  $langs->load("productbatch");
52 }
53 
54 $action = GETPOST('action', 'aZ09');
55 $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
56 $confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation
57 $cancel = GETPOST('cancel', 'alpha');
58 $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : str_replace('_', '', basename(dirname(__FILE__)).basename(__FILE__, '.php')); // To manage different context of search
59 $toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list
60 $backtopage = GETPOST("backtopage", "alpha");
61 $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
62 $show_files = GETPOST('show_files', 'aZ');
63 $mode = GETPOST('mode', 'aZ'); // The output mode ('list', 'kanban', 'hierarchy', 'calendar', ...)
64 
65 $id = GETPOSTINT('id');
66 $ref = GETPOST('ref', 'alpha');
67 $msid = GETPOSTINT('msid');
68 $idproduct = GETPOST('idproduct', 'intcomma');
69 $product_id = GETPOST("product_id", 'intcomma');
70 $show_files = GETPOSTINT('show_files');
71 
72 $search_all = trim((GETPOST('search_all', 'alphanohtml') != '') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'));
73 $search_date_startday = GETPOSTINT('search_date_startday');
74 $search_date_startmonth = GETPOSTINT('search_date_startmonth');
75 $search_date_startyear = GETPOSTINT('search_date_startyear');
76 $search_date_endday = GETPOSTINT('search_date_endday');
77 $search_date_endmonth = GETPOSTINT('search_date_endmonth');
78 $search_date_endyear = GETPOSTINT('search_date_endyear');
79 $search_date_start = dol_mktime(0, 0, 0, GETPOSTINT('search_date_startmonth'), GETPOSTINT('search_date_startday'), GETPOSTINT('search_date_startyear'), 'tzuserrel');
80 $search_date_end = dol_mktime(23, 59, 59, GETPOSTINT('search_date_endmonth'), GETPOSTINT('search_date_endday'), GETPOSTINT('search_date_endyear'), 'tzuserrel');
81 $search_ref = GETPOST('search_ref', 'alpha');
82 $search_movement = GETPOST("search_movement");
83 $search_product_ref = trim(GETPOST("search_product_ref"));
84 $search_product = trim(GETPOST("search_product"));
85 $search_warehouse = trim(GETPOST("search_warehouse"));
86 $search_inventorycode = trim(GETPOST("search_inventorycode"));
87 $search_user = trim(GETPOST("search_user"));
88 $search_batch = trim(GETPOST("search_batch"));
89 $search_qty = trim(GETPOST("search_qty"));
90 $search_type_mouvement = GETPOST('search_type_mouvement');
91 $search_fk_project = GETPOST("search_fk_project");
92 
93 $type = GETPOSTINT("type");
94 
95 // Load variable for pagination
96 $limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
97 $sortfield = GETPOST('sortfield', 'aZ09comma');
98 $sortorder = GETPOST('sortorder', 'aZ09comma');
99 $page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
100 if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) {
101  // If $page is not defined, or '' or -1 or if we click on clear filters
102  $page = 0;
103 }
104 $offset = $limit * $page;
105 $pageprev = $page - 1;
106 $pagenext = $page + 1;
107 
108 if (!$sortfield) {
109  $sortfield = "m.datem";
110 }
111 if (!$sortorder) {
112  $sortorder = "DESC";
113 }
114 
115 $pdluoid = GETPOSTINT('pdluoid');
116 
117 // Initialize technical objects
118 $object = new MouvementStock($db);
119 $extrafields = new ExtraFields($db);
120 $diroutputmassaction = $conf->stock->dir_output.'/temp/massgeneration/'.$user->id;
121 $hookmanager->initHooks(array($contextpage)); // Note that conf->hooks_modules contains array of activated contexes
122 
123 $formfile = new FormFile($db);
124 
125 // Fetch optionals attributes and labels
126 $extrafields->fetch_name_optionals_label($object->table_element);
127 
128 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
129 
130 $arrayfields = array(
131  'm.rowid' => array('label' => "Ref", 'checked' => 1, 'position' => 1),
132  'm.datem' => array('label' => "Date", 'checked' => 1, 'position' => 2),
133  'p.ref' => array('label' => "ProductRef", 'checked' => 1, 'css' => 'maxwidth100', 'position' => 3),
134  'p.label' => array('label' => "ProductLabel", 'checked' => 0, 'position' => 5),
135  'm.batch' => array('label' => "BatchNumberShort", 'checked' => 1, 'position' => 8, 'enabled' => (isModEnabled('productbatch'))),
136  'pl.eatby' => array('label' => "EatByDate", 'checked' => 0, 'position' => 9, 'enabled' => (isModEnabled('productbatch'))),
137  'pl.sellby' => array('label' => "SellByDate", 'checked' => 0, 'position' => 10, 'enabled' => (isModEnabled('productbatch'))),
138  'e.ref' => array('label' => "Warehouse", 'checked' => 1, 'position' => 100, 'enabled' => (!($id > 0))), // If we are on specific warehouse, we hide it
139  'm.fk_user_author' => array('label' => "Author", 'checked' => 0, 'position' => 120),
140  'm.inventorycode' => array('label' => "InventoryCodeShort", 'checked' => 1, 'position' => 130),
141  'm.label' => array('label' => "MovementLabel", 'checked' => 1, 'position' => 140),
142  'm.type_mouvement' => array('label' => "TypeMovement", 'checked' => 0, 'position' => 150),
143  'origin' => array('label' => "Origin", 'checked' => 1, 'position' => 155),
144  'm.fk_projet' => array('label' => 'Project', 'checked' => 0, 'position' => 180),
145  'm.value' => array('label' => "Qty", 'checked' => 1, 'position' => 200),
146  'm.price' => array('label' => "UnitPurchaseValue", 'checked' => 0, 'position' => 210, 'enabled' => (!getDolGlobalInt('STOCK_MOVEMENT_LIST_HIDE_UNIT_PRICE')))
147  //'m.datec'=>array('label'=>"DateCreation", 'checked'=>0, 'position'=>500),
148  //'m.tms'=>array('label'=>"DateModificationShort", 'checked'=>0, 'position'=>500)
149 );
150 
151 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
152 
153 if (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
154  unset($arrayfields['pl.sellby']);
155 }
156 if (getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
157  unset($arrayfields['pl.eatby']);
158 }
159 
160 
161 $tmpwarehouse = new Entrepot($db);
162 if ($id > 0 || !empty($ref)) {
163  $tmpwarehouse->fetch($id, $ref);
164  $id = $tmpwarehouse->id;
165 }
166 
167 
168 // Security check
169 //$result=restrictedArea($user, 'stock', $id, 'entrepot&stock');
170 $result = restrictedArea($user, 'stock');
171 
172 // Security check
173 if (!$user->hasRight('stock', 'mouvement', 'lire')) {
174  accessforbidden();
175 }
176 
177 $uploaddir = $conf->stock->dir_output.'/movements';
178 
179 $permissiontoread = $user->hasRight('stock', 'mouvement', 'lire');
180 $permissiontoadd = $user->hasRight('stock', 'mouvement', 'creer');
181 $permissiontodelete = $user->hasRight('stock', 'mouvement', 'creer'); // There is no deletion permission for stock movement as we should never delete
182 
183 $usercanread = $user->hasRight('stock', 'mouvement', 'lire');
184 $usercancreate = $user->hasRight('stock', 'mouvement', 'creer');
185 $usercandelete = $user->hasRight('stock', 'mouvement', 'creer');
186 
187 $error = 0;
188 
189 
190 /*
191  * Actions
192  */
193 
194 if (GETPOST('cancel', 'alpha')) {
195  $action = 'list';
196  $massaction = '';
197 }
198 if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
199  $massaction = '';
200 }
201 
202 $parameters = array();
203 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
204 if ($reshook < 0) {
205  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
206 }
207 
208 if (empty($reshook)) {
209  // Selection of new fields
210  include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
211 
212  // Purge search criteria
213  if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers
214  $search_date_startday = '';
215  $search_date_startmonth = '';
216  $search_date_startyear = '';
217  $search_date_endday = '';
218  $search_date_endmonth = '';
219  $search_date_endyear = '';
220  $search_date_start = '';
221  $search_date_end = '';
222  $search_ref = '';
223  $search_movement = "";
224  $search_type_mouvement = "";
225  $search_inventorycode = "";
226  $search_product_ref = "";
227  $search_product = "";
228  $search_warehouse = "";
229  $search_user = "";
230  $search_batch = "";
231  $search_qty = '';
232  $search_fk_project = "";
233  $search_all = "";
234  $toselect = array();
235  $search_array_options = array();
236  }
237  if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')
238  || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) {
239  $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation
240  }
241 
242  // Mass actions
243  $objectclass = 'MouvementStock';
244  $objectlabel = 'MouvementStock';
245 
246  if (!$error && $massaction == "builddoc" && $permissiontoread && !GETPOST('button_search')) {
247  if (empty($diroutputmassaction)) {
248  dol_print_error(null, 'include of actions_massactions.inc.php is done but var $diroutputmassaction was not defined');
249  exit;
250  }
251 
252  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
253  require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
254  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
255 
256  $objecttmp = new MouvementStock($db);
257  $listofobjectid = array();
258  foreach ($toselect as $toselectid) {
259  $objecttmp = new MouvementStock($db); // must create new instance because instance is saved into $listofobjectref array for future use
260  $result = $objecttmp->fetch($toselectid);
261  if ($result > 0) {
262  $listofobjectid[$toselectid] = $toselectid;
263  }
264  }
265 
266  $arrayofinclusion = array();
267  foreach ($listofobjectref as $tmppdf) {
268  $arrayofinclusion[] = '^'.preg_quote(dol_sanitizeFileName($tmppdf), '/').'\.pdf$';
269  }
270  foreach ($listofobjectref as $tmppdf) {
271  $arrayofinclusion[] = '^'.preg_quote(dol_sanitizeFileName($tmppdf), '/').'_[a-zA-Z0-9-_]+\.pdf$'; // To include PDF generated from ODX files
272  }
273  $listoffiles = dol_dir_list($uploaddir, 'all', 1, implode('|', $arrayofinclusion), '\.meta$|\.png', 'date', SORT_DESC, 0, true);
274 
275  // Define output language (Here it is not used because we do only merging existing PDF)
276  $outputlangs = $langs;
277  $newlang = '';
278  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
279  $newlang = GETPOST('lang_id', 'aZ09');
280  }
281  //elseif (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && is_object($objecttmp->thirdparty)) { // On massaction, we can have several values for $objecttmp->thirdparty
282  // $newlang = $objecttmp->thirdparty->default_lang;
283  //}
284  if (!empty($newlang)) {
285  $outputlangs = new Translate("", $conf);
286  $outputlangs->setDefaultLang($newlang);
287  }
288 
289  // Create output dir if not exists
290  dol_mkdir($diroutputmassaction);
291 
292  // Defined name of merged file
293  $filename = strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
294  $filename = preg_replace('/\s/', '_', $filename);
295 
296  // Save merged file
297  /*
298  if ($year) {
299  $filename .= '_'.$year;
300  }
301  if ($month) {
302  $filename .= '_'.$month;
303  }
304  */
305  $now = dol_now();
306  $file = $diroutputmassaction.'/'.$filename.'_'.dol_print_date($now, 'dayhourlog').'.pdf';
307 
308 
309  // Create PDF
310  // TODO Create the pdf including list of movement ids found into $listofobjectid
311  // ...
312 
313 
314  if (!$error) {
315  $langs->load("exports");
316  setEventMessage($langs->trans('FeatureNotYetAvailable'));
317  //setEventMessages($langs->trans('FileSuccessfullyBuilt', $filename.'_'.dol_print_date($now, 'dayhourlog')), null, 'mesgs');
318  }
319 
320  $massaction = '';
321  $action = '';
322  }
323 
324  include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
325 }
326 
327 if ($action == 'update_extras' && $permissiontoadd) {
328  $tmpwarehouse->oldcopy = dol_clone($tmpwarehouse, 2);
329 
330  // Fill array 'array_options' with data from update form
331  $ret = $extrafields->setOptionalsFromPost(null, $tmpwarehouse, GETPOST('attribute', 'restricthtml'));
332  if ($ret < 0) {
333  $error++;
334  }
335  if (!$error) {
336  $result = $tmpwarehouse->insertExtraFields();
337  if ($result < 0) {
338  setEventMessages($tmpwarehouse->error, $tmpwarehouse->errors, 'errors');
339  $error++;
340  }
341  }
342  if ($error) {
343  $action = 'edit_extras';
344  }
345 }
346 
347 // Correct stock
348 if ($action == "correct_stock" && $permissiontoadd) {
349  $product = new Product($db);
350  if (!empty($product_id)) {
351  $result = $product->fetch($product_id);
352  }
353 
354  $error = 0;
355 
356  if (empty($product_id)) {
357  $error++;
358  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
359  $action = 'correction';
360  }
361  if (!is_numeric(GETPOST("nbpiece"))) {
362  $error++;
363  setEventMessages($langs->trans("ErrorFieldMustBeANumeric", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
364  $action = 'correction';
365  }
366 
367  if (!$error) {
368  $origin_element = '';
369  $origin_id = null;
370 
371  if (GETPOSTINT('projectid')) {
372  $origin_element = 'project';
373  $origin_id = GETPOSTINT('projectid');
374  }
375 
376  if ($product->hasbatch()) {
377  $batch = GETPOST('batch_number', 'alphanohtml');
378 
379  //$eatby=GETPOST('eatby');
380  //$sellby=GETPOST('sellby');
381  $eatby = dol_mktime(0, 0, 0, GETPOSTINT('eatbymonth'), GETPOSTINT('eatbyday'), GETPOSTINT('eatbyyear'));
382  $sellby = dol_mktime(0, 0, 0, GETPOSTINT('sellbymonth'), GETPOSTINT('sellbyday'), GETPOSTINT('sellbyyear'));
383 
384  $result = $product->correct_stock_batch(
385  $user,
386  $id,
387  GETPOSTINT("nbpiece"),
388  GETPOSTINT("mouvement"),
389  GETPOST("label", 'alphanohtml'),
390  price2num(GETPOST('unitprice'), 'MT'),
391  $eatby,
392  $sellby,
393  $batch,
394  GETPOST('inventorycode', 'alphanohtml'),
395  $origin_element,
396  $origin_id,
397  0,
398  $extrafields
399  ); // We do not change value of stock for a correction
400  } else {
401  $result = $product->correct_stock(
402  $user,
403  $id,
404  GETPOSTINT("nbpiece"),
405  GETPOSTINT("mouvement"),
406  GETPOST("label", 'alphanohtml'),
407  price2num(GETPOST('unitprice'), 'MT'),
408  GETPOST('inventorycode', 'alphanohtml'),
409  $origin_element,
410  $origin_id,
411  0,
412  $extrafields
413  ); // We do not change value of stock for a correction
414  }
415 
416  if ($result > 0) {
417  header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
418  exit;
419  } else {
420  $error++;
421  setEventMessages($product->error, $product->errors, 'errors');
422  $action = 'correction';
423  }
424  }
425 
426  if (!$error) {
427  $action = '';
428  }
429 }
430 
431 // Transfer stock from a warehouse to another warehouse
432 if ($action == "transfert_stock" && $permissiontoadd && !$cancel) {
433  $error = 0;
434  $product = new Product($db);
435  if (!empty($product_id)) {
436  $result = $product->fetch($product_id);
437  }
438 
439  if (!(GETPOSTINT("id_entrepot_destination") > 0)) {
440  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
441  $error++;
442  $action = 'transfert';
443  }
444  if (empty($product_id)) {
445  $error++;
446  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
447  $action = 'transfert';
448  }
449  if (!GETPOSTINT("nbpiece")) {
450  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
451  $error++;
452  $action = 'transfert';
453  }
454  if ($id == GETPOSTINT("id_entrepot_destination")) {
455  setEventMessages($langs->trans("ErrorSrcAndTargetWarehouseMustDiffers"), null, 'errors');
456  $error++;
457  $action = 'transfert';
458  }
459 
460  if (isModEnabled('productbatch')) {
461  $product = new Product($db);
462  $result = $product->fetch($product_id);
463 
464  if ($product->hasbatch() && !GETPOST("batch_number")) {
465  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("batch_number")), null, 'errors');
466  $error++;
467  $action = 'transfert';
468  }
469  }
470 
471  if (!$error) {
472  if ($id) {
473  $warehouse = new Entrepot($db);
474  $result = $warehouse->fetch($id);
475 
476  $db->begin();
477 
478  $product->load_stock('novirtual'); // Load array product->stock_warehouse
479 
480  // Define value of products moved
481  $pricesrc = 0;
482  if (isset($product->pmp)) {
483  $pricesrc = $product->pmp;
484  }
485  $pricedest = $pricesrc;
486 
487  if ($product->hasbatch()) {
488  $pdluo = new Productbatch($db);
489 
490  if ($pdluoid > 0) {
491  $result = $pdluo->fetch($pdluoid);
492  if ($result) {
493  $srcwarehouseid = $pdluo->warehouseid;
494  $batch = $pdluo->batch;
495  $eatby = $pdluo->eatby;
496  $sellby = $pdluo->sellby;
497  } else {
498  setEventMessages($pdluo->error, $pdluo->errors, 'errors');
499  $error++;
500  }
501  } else {
502  $srcwarehouseid = $id;
503  $batch = GETPOST('batch_number', 'alphanohtml');
504  $eatby = $d_eatby;
505  $sellby = $d_sellby;
506  }
507 
508  if (!$error) {
509  // Remove stock
510  $result1 = $product->correct_stock_batch(
511  $user,
512  $srcwarehouseid,
513  GETPOSTINT("nbpiece"),
514  1,
515  GETPOST("label", 'san_alpha'),
516  $pricesrc,
517  $eatby,
518  $sellby,
519  $batch,
520  GETPOST('inventorycode'),
521  '',
522  null,
523  0,
524  $extrafields
525  );
526  // Add stock
527  $result2 = $product->correct_stock_batch(
528  $user,
529  GETPOSTINT("id_entrepot_destination"),
530  GETPOSTINT("nbpiece"),
531  0,
532  GETPOST("label", 'san_alpha'),
533  $pricedest,
534  $eatby,
535  $sellby,
536  $batch,
537  GETPOST('inventorycode', 'alphanohtml'),
538  '',
539  null,
540  0,
541  $extrafields
542  );
543  }
544  } else {
545  // Remove stock
546  $result1 = $product->correct_stock(
547  $user,
548  $id,
549  GETPOST("nbpiece"),
550  1,
551  GETPOST("label", 'san_alpha'),
552  $pricesrc,
553  GETPOST('inventorycode', 'alphanohtml'),
554  '',
555  null,
556  0,
557  $extrafields
558  );
559 
560  // Add stock
561  $result2 = $product->correct_stock(
562  $user,
563  GETPOST("id_entrepot_destination"),
564  GETPOST("nbpiece"),
565  0,
566  GETPOST("label", 'san_alpha'),
567  $pricedest,
568  GETPOST('inventorycode', 'alphanohtml'),
569  '',
570  null,
571  0,
572  $extrafields
573  );
574  }
575  if (!$error && $result1 >= 0 && $result2 >= 0) {
576  $db->commit();
577 
578  if ($backtopage) {
579  header("Location: ".$backtopage);
580  exit;
581  } else {
582  header("Location: movement_list.php?id=".$warehouse->id);
583  exit;
584  }
585  } else {
586  setEventMessages($product->error, $product->errors, 'errors');
587  $db->rollback();
588  $action = 'transfert';
589  }
590  }
591  }
592 }
593 
594 // reverse movement of stock
595 if ($action == 'confirm_reverse' && $confirm == "yes" && $permissiontoadd) {
596  $toselect = array_map('intval', $toselect);
597 
598  $sql = "SELECT rowid, label, inventorycode, datem";
599  $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement";
600  $sql .= " WHERE rowid IN (";
601  foreach ($toselect as $id) {
602  $sql .= ((int) $id).",";
603  }
604  $sql = rtrim($sql, ',');
605  $sql .= ")";
606 
607  $resql = $db->query($sql);
608  if ($resql) {
609  $num = $db->num_rows($resql);
610  $i = 0;
611  while ($i < $num) {
612  $obj = $db->fetch_object($resql);
613  $object->fetch($obj->rowid);
614  $reverse = $object->reverseMouvement();
615  if ($reverse < 0) {
616  $hasError = true;
617  } else {
618  $hasSuccess = true;
619  }
620  $i++;
621  }
622  if ($hasError) {
623  setEventMessages($langs->trans("WarningAlreadyReverse", $langs->transnoentities($idAlreadyReverse)), null, 'warnings');
624  }
625  if ($hasSuccess) {
626  setEventMessages($langs->trans("ReverseConfirmed"), null);
627  }
628  header("Location: ".$_SERVER["PHP_SELF"]);
629  exit;
630  }
631 }
632 
633 /*
634  * View
635  */
636 
637 $form = new Form($db);
638 $formproduct = new FormProduct($db);
639 if (isModEnabled('project')) {
640  $formproject = new FormProjets($db);
641 }
642 $productlot = new Productlot($db);
643 $productstatic = new Product($db);
644 $warehousestatic = new Entrepot($db);
645 
646 $userstatic = new User($db);
647 
648 $now = dol_now();
649 
650 // Build and execute select
651 // --------------------------------------------------------------------
652 $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.tosell, p.tobuy, p.tobatch, p.fk_product_type as type, p.entity,";
653 $sql .= " e.ref as warehouse_ref, e.rowid as entrepot_id, e.lieu, e.fk_parent, e.statut,";
654 $sql .= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,";
655 $sql .= " m.batch, m.price,";
656 $sql .= " m.type_mouvement,";
657 $sql .= " m.fk_projet as fk_project,";
658 $sql .= " pl.rowid as lotid, pl.eatby, pl.sellby,";
659 $sql .= " u.login, u.photo, u.lastname, u.firstname, u.email as user_email, u.statut as user_status";
660 // Add fields from extrafields
661 if (!empty($extrafields->attributes[$object->table_element]['label'])) {
662  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
663  $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
664  }
665 }
666 // Add fields from hooks
667 $parameters = array();
668 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
669 $sql .= $hookmanager->resPrint;
670 $sql = preg_replace('/,\s*$/', '', $sql);
671 
672 $sqlfields = $sql; // $sql fields to remove for count total
673 
674 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
675 $sql .= " ".MAIN_DB_PREFIX."product as p,";
676 $sql .= " ".MAIN_DB_PREFIX."stock_mouvement as m";
677 if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
678  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (m.rowid = ef.fk_object)";
679 }
680 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON m.fk_user_author = u.rowid";
681 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON m.batch = pl.batch AND m.fk_product = pl.fk_product";
682 
683 // Add table from hooks
684 $parameters = array();
685 $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
686 $sql .= $hookmanager->resPrint;
687 
688 $sql .= " WHERE m.fk_product = p.rowid";
689 if ($msid > 0) {
690  $sql .= " AND m.rowid = ".((int) $msid);
691 }
692 $sql .= " AND m.fk_entrepot = e.rowid";
693 $sql .= " AND e.entity IN (".getEntity('stock').")";
694 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
695  $sql .= " AND p.fk_product_type = 0";
696 }
697 if ($id > 0) {
698  $sql .= " AND e.rowid = ".((int) $id);
699 }
700 if (!empty($search_date_start)) {
701  $sql .= " AND m.datem >= '" . $db->idate($search_date_start) . "'";
702 }
703 if (!empty($search_date_end)) {
704  $sql .= " AND m.datem <= '" . $db->idate($search_date_end) . "'";
705 }
706 if ($idproduct > 0) {
707  $sql .= " AND p.rowid = ".((int) $idproduct);
708 }
709 if (!empty($search_ref)) {
710  $sql .= natural_search('m.rowid', $search_ref, 1);
711 }
712 if (!empty($search_movement)) {
713  $sql .= natural_search('m.label', $search_movement);
714 }
715 if (!empty($search_inventorycode)) {
716  $sql .= natural_search('m.inventorycode', $search_inventorycode);
717 }
718 if (!empty($search_product_ref)) {
719  $sql .= natural_search('p.ref', $search_product_ref);
720 }
721 if (!empty($search_product)) {
722  $sql .= natural_search('p.label', $search_product);
723 }
724 if ($search_warehouse != '' && $search_warehouse != '-1') {
725  $sql .= natural_search('e.rowid', $search_warehouse, 2);
726 }
727 if (!empty($search_user)) {
728  $sql .= natural_search(array('u.lastname', 'u.firstname', 'u.login'), $search_user);
729 }
730 if (!empty($search_batch)) {
731  $sql .= natural_search('m.batch', $search_batch);
732 }
733 if (!empty($product_id) && $product_id != '-1') {
734  $sql .= natural_search('p.rowid', $product_id);
735 }
736 if (!empty($search_fk_project) && $search_fk_project != '-1') {
737  $sql .= natural_search('m.fk_projet', $search_fk_project);
738 }
739 if ($search_qty != '') {
740  $sql .= natural_search('m.value', $search_qty, 1);
741 }
742 if ($search_type_mouvement != '' && $search_type_mouvement != '-1') {
743  $sql .= natural_search('m.type_mouvement', $search_type_mouvement, 2);
744 }
745 // Add where from extra fields
746 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
747 // Add where from hooks
748 $parameters = array();
749 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
750 $sql .= $hookmanager->resPrint;
751 
752 // Count total nb of records
753 $nbtotalofrecords = '';
754 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
755  /* The fast and low memory method to get and count full list converts the sql into a sql count */
756  $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql);
757  $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount);
758  $resql = $db->query($sqlforcount);
759  if ($resql) {
760  $objforcount = $db->fetch_object($resql);
761  $nbtotalofrecords = $objforcount->nbtotalofrecords;
762  } else {
763  dol_print_error($db);
764  }
765 
766  if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 0
767  $page = 0;
768  $offset = 0;
769  }
770  $db->free($resql);
771 }
772 
773 // Complete request and execute it with limit
774 $sql .= $db->order($sortfield, $sortorder);
775 if ($limit) {
776  $sql .= $db->plimit($limit + 1, $offset);
777 }
778 
779 $resql = $db->query($sql);
780 if (!$resql) {
781  dol_print_error($db);
782  exit;
783 }
784 
785 $num = $db->num_rows($resql);
786 
787 
788 $product = new Product($db);
789 $warehouse = new Entrepot($db);
790 
791 if ($idproduct > 0) {
792  $product->fetch($idproduct);
793 }
794 if ($id > 0 || $ref) {
795  $result = $warehouse->fetch($id, $ref);
796  if ($result < 0) {
797  dol_print_error($db);
798  }
799 }
800 
801 
802 // Output page
803 // --------------------------------------------------------------------
804 
805 $i = 0;
806 $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
807 if ($msid) {
808  $title = $langs->trans('StockMovementForId', $msid);
809 } else {
810  $title = $langs->trans("ListOfStockMovements");
811  if ($id) {
812  if (!empty($warehouse->ref)) {
813  $title .= ' ('.$warehouse->ref.')';
814  } else {
815  $title .= ' ('.$langs->trans("ForThisWarehouse").')';
816  }
817  }
818 }
819 
820 
821 // Output page
822 // --------------------------------------------------------------------
823 
824 llxHeader('', $title, $help_url);
825 
826 /*
827  * Show tab only if we ask a particular warehouse
828  */
829 if ($warehouse->id > 0) {
830  $head = stock_prepare_head($warehouse);
831 
832  print dol_get_fiche_head($head, 'movements', $langs->trans("Warehouse"), -1, 'stock');
833 
834 
835  $linkback = '<a href="'.DOL_URL_ROOT.'/product/stock/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
836 
837  $morehtmlref = '<div class="refidno">';
838  $morehtmlref .= $langs->trans("LocationSummary").' : '.$warehouse->lieu;
839 
840  // Project
841  if (isModEnabled('project')) {
842  $langs->load("projects");
843  $morehtmlref .= '<br>'.img_picto('', 'project').' '.$langs->trans('Project').' ';
844  if ($usercancreate && 1 == 2) {
845  if ($action != 'classify') {
846  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$warehouse->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> : ';
847  }
848  if ($action == 'classify') {
849  $projectid = $warehouse->fk_project;
850  $morehtmlref .= '<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$warehouse->id.'">';
851  $morehtmlref .= '<input type="hidden" name="action" value="classin">';
852  $morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
853  $morehtmlref .= $formproject->select_projects(($socid > 0 ? $socid : -1), $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
854  $morehtmlref .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
855  $morehtmlref .= '</form>';
856  } else {
857  $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$warehouse->id, $warehouse->socid, $warehouse->fk_project, 'none', 0, 0, 0, 1, '', 'maxwidth300');
858  }
859  } else {
860  if (!empty($warehouse->fk_project)) {
861  $proj = new Project($db);
862  $proj->fetch($warehouse->fk_project);
863  $morehtmlref .= ' : '.$proj->getNomUrl(1);
864  if ($proj->title) {
865  $morehtmlref .= ' - '.$proj->title;
866  }
867  } else {
868  $morehtmlref .= '';
869  }
870  }
871  }
872  $morehtmlref .= '</div>';
873 
874  $shownav = 1;
875  if ($user->socid && !in_array('stock', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
876  $shownav = 0;
877  }
878 
879  dol_banner_tab($warehouse, 'ref', $linkback, $shownav, 'ref', 'ref', $morehtmlref);
880 
881 
882  print '<div class="fichecenter">';
883  print '<div class="fichehalfleft">';
884  print '<div class="underbanner clearboth"></div>';
885 
886  print '<table class="border centpercent tableforfield">';
887 
888  print '<tr>';
889 
890  // Description
891  print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>'.dol_htmlentitiesbr($warehouse->description).'</td></tr>';
892 
893  $calcproductsunique = $warehouse->nb_different_products();
894  $calcproducts = $warehouse->nb_products();
895 
896  // Total nb of different products
897  print '<tr><td>'.$langs->trans("NumberOfDifferentProducts").'</td><td>';
898  print empty($calcproductsunique['nb']) ? '0' : $calcproductsunique['nb'];
899  print "</td></tr>";
900 
901  // Nb of products
902  print '<tr><td>'.$langs->trans("NumberOfProducts").'</td><td>';
903  $valtoshow = price2num($calcproducts['nb'], 'MS');
904  print empty($valtoshow) ? '0' : $valtoshow;
905  print "</td></tr>";
906 
907  print '</table>';
908 
909  print '</div>';
910  print '<div class="fichehalfright">';
911  print '<div class="underbanner clearboth"></div>';
912 
913  print '<table class="border centpercent tableforfield">';
914 
915  // Value
916  print '<tr><td class="titlefield">'.$langs->trans("EstimatedStockValueShort").'</td><td>';
917  print price((empty($calcproducts['value']) ? '0' : price2num($calcproducts['value'], 'MT')), 0, $langs, 0, -1, -1, $conf->currency);
918  print "</td></tr>";
919 
920  // Last movement
921  $sql = "SELECT MAX(m.datem) as datem";
922  $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
923  $sql .= " WHERE m.fk_entrepot = ".((int) $warehouse->id);
924  $resqlbis = $db->query($sql);
925  if ($resqlbis) {
926  $objbis = $db->fetch_object($resqlbis);
927  $lastmovementdate = $db->jdate($objbis->datem);
928  } else {
929  dol_print_error($db);
930  }
931 
932  print '<tr><td>'.$langs->trans("LastMovement").'</td><td>';
933  if ($lastmovementdate) {
934  print dol_print_date($lastmovementdate, 'dayhour');
935  } else {
936  print $langs->trans("None");
937  }
938  print "</td></tr>";
939 
940  // Other attributes
941  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
942 
943  // Categories
944  if (isModEnabled('category')) {
945  print '<tr><td valign="middle">'.$langs->trans("Categories").'</td><td colspan="3">';
946  print $form->showCategories($warehouse->id, Categorie::TYPE_WAREHOUSE, 1);
947  print "</td></tr>";
948  }
949 
950  print "</table>";
951 
952  print '</div>';
953  print '</div>';
954 
955  print '<div class="clearboth"></div>';
956 
957  print dol_get_fiche_end();
958 }
959 
960 
961 // Correct stock
962 if ($action == "correction") {
963  include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stockcorrection.tpl.php';
964  print '<br>';
965 }
966 
967 // Transfer of units
968 if ($action == "transfert") {
969  include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stocktransfer.tpl.php';
970  print '<br>';
971 }
972 
973 
974 // Action bar
975 if ((empty($action) || $action == 'list') && $id > 0) {
976  print "<div class=\"tabsAction\">\n";
977 
978  $parameters = array();
979  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been
980  // modified by hook
981  if (empty($reshook)) {
982  if ($user->hasRight('stock', 'mouvement', 'creer')) {
983  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=correction">'.$langs->trans("CorrectStock").'</a>';
984  }
985 
986  if ($user->hasRight('stock', 'mouvement', 'creer')) {
987  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=transfert">'.$langs->trans("TransferStock").'</a>';
988  }
989  }
990 
991  print '</div><br>';
992 }
993 
994 $arrayofselected = is_array($toselect) ? $toselect : array();
995 
996 $param = '';
997 if (!empty($mode)) {
998  $param .= '&mode='.urlencode($mode);
999 }
1000 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1001  $param .= '&contextpage='.urlencode($contextpage);
1002 }
1003 if ($limit > 0 && $limit != $conf->liste_limit) {
1004  $param .= '&limit='.((int) $limit);
1005 }
1006 if ($id > 0) {
1007  $param .= '&id='.urlencode((string) ($id));
1008 }
1009 if ($show_files) {
1010  $param .= '&show_files='.urlencode((string) ($show_files));
1011 }
1012 if ($search_date_startday) {
1013  $param .= '&search_date_startday='.urlencode((string) ($search_date_startday));
1014 }
1015 if ($search_date_startmonth) {
1016  $param .= '&search_date_startmonth='.urlencode((string) ($search_date_startmonth));
1017 }
1018 if ($search_date_startyear) {
1019  $param .= '&search_date_startyear='.urlencode((string) ($search_date_startyear));
1020 }
1021 if ($search_date_endday) {
1022  $param .= '&search_date_endday='.urlencode((string) ($search_date_endday));
1023 }
1024 if ($search_date_endmonth) {
1025  $param .= '&search_date_endmonth='.urlencode((string) ($search_date_endmonth));
1026 }
1027 if ($search_date_endyear) {
1028  $param .= '&search_date_endyear='.urlencode((string) ($search_date_endyear));
1029 }
1030 if ($search_movement) {
1031  $param .= '&search_movement='.urlencode($search_movement);
1032 }
1033 if ($search_inventorycode) {
1034  $param .= '&search_inventorycode='.urlencode($search_inventorycode);
1035 }
1036 if ($search_type_mouvement) {
1037  $param .= '&search_type_mouvement='.urlencode($search_type_mouvement);
1038 }
1039 if ($search_product_ref) {
1040  $param .= '&search_product_ref='.urlencode($search_product_ref);
1041 }
1042 if ($search_product) {
1043  $param .= '&search_product='.urlencode($search_product);
1044 }
1045 if ($search_batch) {
1046  $param .= '&search_batch='.urlencode($search_batch);
1047 }
1048 if ($search_warehouse > 0) {
1049  $param .= '&search_warehouse='.urlencode($search_warehouse);
1050 }
1051 if ($search_user) {
1052  $param .= '&search_user='.urlencode($search_user);
1053 }
1054 if ($idproduct > 0) {
1055  $param .= '&idproduct='.urlencode((string) ($idproduct));
1056 }
1057 if ($search_fk_project != '' && $search_fk_project != '-1') {
1058  $param .= '&search_fk_project='.urlencode((string) ($search_fk_project));
1059 }
1060 // Add $param from extra fields
1061 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
1062 // Add $param from hooks
1063 $parameters = array('param' => &$param);
1064 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1065 $param .= $hookmanager->resPrint;
1066 
1067 // List of mass actions available
1068 $arrayofmassactions = array();
1069 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
1070  $arrayofmassactions['builddoc'] = img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("GeneratePDF");
1071 }
1072 // By default, we should never accept deletion of stock movement
1073 if (getDolGlobalString('STOCK_ALLOW_DELETE_OF_MOVEMENT') && $permissiontodelete) {
1074  $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
1075 }
1076 if (!empty($permissiontoadd)) {
1077  $arrayofmassactions['prereverse'] = img_picto('', 'add', 'class="pictofixedwidth"').$langs->trans("Reverse");
1078 }
1079 if (GETPOSTINT('nomassaction') || in_array($massaction, array('presend', 'predelete', 'prereverse'))) {
1080  $arrayofmassactions = array();
1081 }
1082 
1083 $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
1084 
1085 print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">'."\n";
1086 if ($optioncss != '') {
1087  print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
1088 }
1089 print '<input type="hidden" name="token" value="'.newToken().'">';
1090 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
1091 print '<input type="hidden" name="action" value="list">';
1092 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
1093 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
1094 print '<input type="hidden" name="type" value="'.$type.'">';
1095 print '<input type="hidden" name="page" value="'.$page.'">';
1096 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
1097 print '<input type="hidden" name="page_y" value="">';
1098 print '<input type="hidden" name="mode" value="'.$mode.'">';
1099 if ($id > 0) {
1100  print '<input type="hidden" name="id" value="'.$id.'">';
1101 }
1102 
1103 
1104 $newcardbutton = '';
1105 
1106 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'movement', 0, '', '', $limit, 0, 0, 1);
1107 
1108 // Add code for pre mass action (confirmation or email presend form)
1109 $topicmail = "SendStockMovement";
1110 $modelmail = "movementstock";
1111 $objecttmp = new MouvementStock($db);
1112 $trackid = 'mov'.$warehouse->id;
1113 include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
1114 if ($massaction == 'prereverse') {
1115  print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassReverse"), $langs->trans("ConfirmMassReverseQuestion", count($toselect)), "confirm_reverse", null, '', 0, 200, 500, 1, 'Yes');
1116 }
1117 
1118 
1119 if ($search_all) {
1120  $setupstring = '';
1121  if (!isset($fieldstosearchall) || !is_array($fieldstosearchall)) {
1122  // Ensure $fieldstosearchall is array
1123  $fieldstosearchall = array();
1124  }
1125  foreach ($fieldstosearchall as $key => $val) {
1126  $fieldstosearchall[$key] = $langs->trans($val);
1127  $setupstring .= $key."=".$val.";";
1128  }
1129  print '<!-- Search done like if STOCK_QUICKSEARCH_ON_FIELDS = '.$setupstring.' -->'."\n";
1130  print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $search_all).implode(', ', $fieldstosearchall).'</div>'."\n";
1131 }
1132 
1133 $moreforfilter = '';
1134 
1135 $parameters = array('arrayfields' => &$arrayfields);
1136 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1137 if (empty($reshook)) {
1138  $moreforfilter .= $hookmanager->resPrint;
1139 } else {
1140  $moreforfilter = $hookmanager->resPrint;
1141 }
1142 
1143 if (!empty($moreforfilter)) {
1144  print '<div class="liste_titre liste_titre_bydiv centpercent">';
1145  print $moreforfilter;
1146  print '</div>';
1147 }
1148 
1149 $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
1150 $htmlofselectarray = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields with user setup
1151 $selectedfields = ($mode != 'kanban' ? $htmlofselectarray : '');
1152 $selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
1153 
1154 print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you don't need reserved height for your table
1155 print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
1156 
1157 // Fields title search
1158 // --------------------------------------------------------------------
1159 print '<tr class="liste_titre">';
1160 // Action column
1161 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1162  print '<td class="liste_titre center maxwidthsearch">';
1163  $searchpicto = $form->showFilterButtons('left');
1164  print $searchpicto;
1165  print '</td>';
1166 }
1167 if (!empty($arrayfields['m.rowid']['checked'])) {
1168  // Ref
1169  print '<td class="liste_titre left">';
1170  print '<input class="flat maxwidth40" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
1171  print '</td>';
1172 }
1173 if (!empty($arrayfields['m.datem']['checked'])) {
1174  // Date
1175  print '<td class="liste_titre center">';
1176  print '<div class="nowrapfordate">';
1177  print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'), 'tzuserrel');
1178  print '</div>';
1179  print '<div class="nowrapfordate">';
1180  print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'), 'tzuserrel');
1181  print '</div>';
1182  print '</td>';
1183 }
1184 if (!empty($arrayfields['p.ref']['checked'])) {
1185  // Product Ref
1186  print '<td class="liste_titre left">';
1187  print '<input class="flat maxwidth75" type="text" name="search_product_ref" value="'.dol_escape_htmltag($idproduct ? $product->ref : $search_product_ref).'">';
1188  print '</td>';
1189 }
1190 if (!empty($arrayfields['p.label']['checked'])) {
1191  // Product label
1192  print '<td class="liste_titre left">';
1193  print '<input class="flat maxwidth100" type="text" name="search_product" value="'.dol_escape_htmltag($idproduct ? $product->label : $search_product).'">';
1194  print '</td>';
1195 }
1196 // Batch
1197 if (!empty($arrayfields['m.batch']['checked'])) {
1198  print '<td class="liste_titre center"><input class="flat maxwidth75" type="text" name="search_batch" value="'.dol_escape_htmltag($search_batch).'"></td>';
1199 }
1200 if (!empty($arrayfields['pl.eatby']['checked'])) {
1201  print '<td class="liste_titre left">';
1202  print '</td>';
1203 }
1204 if (!empty($arrayfields['pl.sellby']['checked'])) {
1205  print '<td class="liste_titre left">';
1206  print '</td>';
1207 }
1208 // Warehouse
1209 if (!empty($arrayfields['e.ref']['checked'])) {
1210  print '<td class="liste_titre maxwidthonsmartphone left">';
1211  //print '<input class="flat" type="text" size="8" name="search_warehouse" value="'.($search_warehouse).'">';
1212  print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
1213  print '</td>';
1214 }
1215 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1216  // Author
1217  print '<td class="liste_titre left">';
1218  print '<input class="flat" type="text" size="6" name="search_user" value="'.dol_escape_htmltag($search_user).'">';
1219  print '</td>';
1220 }
1221 if (!empty($arrayfields['m.inventorycode']['checked'])) {
1222  // Inventory code
1223  print '<td class="liste_titre left">';
1224  print '<input class="flat" type="text" size="4" name="search_inventorycode" value="'.dol_escape_htmltag($search_inventorycode).'">';
1225  print '</td>';
1226 }
1227 if (!empty($arrayfields['m.label']['checked'])) {
1228  // Label of movement
1229  print '<td class="liste_titre left">';
1230  print '<input class="flat" type="text" size="8" name="search_movement" value="'.dol_escape_htmltag($search_movement).'">';
1231  print '</td>';
1232 }
1233 if (!empty($arrayfields['origin']['checked'])) {
1234  // Origin of movement
1235  print '<td class="liste_titre left">';
1236  print '&nbsp; ';
1237  print '</td>';
1238 }
1239 if (!empty($arrayfields['m.fk_projet']['checked'])) {
1240  // fk_project
1241  print '<td class="liste_titre" align="left">';
1242  print $warehouse->showInputField($warehouse->fields['fk_project'], 'fk_project', $search_fk_project, '', '', 'search_', 'maxwidth125', 1);
1243  print '</td>';
1244 }
1245 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1246  // Type of movement
1247  print '<td class="liste_titre center">';
1248  //print '<input class="flat" type="text" size="3" name="search_type_mouvement" value="'.dol_escape_htmltag($search_type_mouvement).'">';
1249  print '<select id="search_type_mouvement" name="search_type_mouvement" class="maxwidth150">';
1250  print '<option value="" '.(($search_type_mouvement == "") ? 'selected="selected"' : '').'>&nbsp;</option>';
1251  print '<option value="0" '.(($search_type_mouvement == "0") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</option>';
1252  print '<option value="1" '.(($search_type_mouvement == "1") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</option>';
1253  print '<option value="2" '.(($search_type_mouvement == "2") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecrease').'</option>';
1254  print '<option value="3" '.(($search_type_mouvement == "3") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncrease').'</option>';
1255  print '</select>';
1256  print ajax_combobox('search_type_mouvement');
1257  // TODO: add new function $formentrepot->selectTypeOfMovement(...) like
1258  // print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
1259  print '</td>';
1260 }
1261 if (!empty($arrayfields['m.value']['checked'])) {
1262  // Qty
1263  print '<td class="liste_titre right">';
1264  print '<input class="flat" type="text" size="4" name="search_qty" value="'.dol_escape_htmltag($search_qty).'">';
1265  print '</td>';
1266 }
1267 if (!empty($arrayfields['m.price']['checked'])) {
1268  // Price
1269  print '<td class="liste_titre" align="left">';
1270  print '&nbsp; ';
1271  print '</td>';
1272 }
1273 
1274 // Extra fields
1275 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
1276 
1277 // Fields from hook
1278 $parameters = array('arrayfields' => $arrayfields);
1279 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1280 print $hookmanager->resPrint;
1281 // Date creation
1282 if (!empty($arrayfields['m.datec']['checked'])) {
1283  print '<td class="liste_titre">';
1284  print '</td>';
1285 }
1286 // Date modification
1287 if (!empty($arrayfields['m.tms']['checked'])) {
1288  print '<td class="liste_titre">';
1289  print '</td>';
1290 }
1291 // Action column
1292 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1293  print '<td class="liste_titre center maxwidthsearch">';
1294  $searchpicto = $form->showFilterButtons();
1295  print $searchpicto;
1296  print '</td>';
1297 }
1298 print '</tr>'."\n";
1299 
1300 $totalarray = array();
1301 $totalarray['nbfield'] = 0;
1302 
1303 // Fields title label
1304 // --------------------------------------------------------------------
1305 print '<tr class="liste_titre">';
1306 // Action column
1307 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1308  print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n";
1309  $totalarray['nbfield']++;
1310 }
1311 if (!empty($arrayfields['m.rowid']['checked'])) {
1312  print_liste_field_titre($arrayfields['m.rowid']['label'], $_SERVER["PHP_SELF"], 'm.rowid', '', $param, '', $sortfield, $sortorder);
1313 }
1314 if (!empty($arrayfields['m.datem']['checked'])) {
1315  print_liste_field_titre($arrayfields['m.datem']['label'], $_SERVER["PHP_SELF"], 'm.datem', '', $param, '', $sortfield, $sortorder, 'center ');
1316 }
1317 if (!empty($arrayfields['p.ref']['checked'])) {
1318  print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder);
1319 }
1320 if (!empty($arrayfields['p.label']['checked'])) {
1321  print_liste_field_titre($arrayfields['p.label']['label'], $_SERVER["PHP_SELF"], 'p.label', '', $param, '', $sortfield, $sortorder);
1322 }
1323 if (!empty($arrayfields['m.batch']['checked'])) {
1324  print_liste_field_titre($arrayfields['m.batch']['label'], $_SERVER["PHP_SELF"], 'm.batch', '', $param, '', $sortfield, $sortorder, 'center ');
1325 }
1326 if (!empty($arrayfields['pl.eatby']['checked'])) {
1327  print_liste_field_titre($arrayfields['pl.eatby']['label'], $_SERVER["PHP_SELF"], 'pl.eatby', '', $param, '', $sortfield, $sortorder, 'center ');
1328 }
1329 if (!empty($arrayfields['pl.sellby']['checked'])) {
1330  print_liste_field_titre($arrayfields['pl.sellby']['label'], $_SERVER["PHP_SELF"], 'pl.sellby', '', $param, '', $sortfield, $sortorder, 'center ');
1331 }
1332 if (!empty($arrayfields['e.ref']['checked'])) {
1333  // We are on a specific warehouse card, no filter on other should be possible
1334  print_liste_field_titre($arrayfields['e.ref']['label'], $_SERVER["PHP_SELF"], "e.ref", "", $param, "", $sortfield, $sortorder);
1335 }
1336 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1337  print_liste_field_titre($arrayfields['m.fk_user_author']['label'], $_SERVER["PHP_SELF"], "m.fk_user_author", "", $param, "", $sortfield, $sortorder);
1338 }
1339 if (!empty($arrayfields['m.inventorycode']['checked'])) {
1340  print_liste_field_titre($arrayfields['m.inventorycode']['label'], $_SERVER["PHP_SELF"], "m.inventorycode", "", $param, "", $sortfield, $sortorder);
1341 }
1342 if (!empty($arrayfields['m.label']['checked'])) {
1343  print_liste_field_titre($arrayfields['m.label']['label'], $_SERVER["PHP_SELF"], "m.label", "", $param, "", $sortfield, $sortorder);
1344 }
1345 if (!empty($arrayfields['origin']['checked'])) {
1346  print_liste_field_titre($arrayfields['origin']['label'], $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder);
1347 }
1348 if (!empty($arrayfields['m.fk_projet']['checked'])) {
1349  print_liste_field_titre($arrayfields['m.fk_projet']['label'], $_SERVER["PHP_SELF"], "m.fk_projet", "", $param, '', $sortfield, $sortorder);
1350 }
1351 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1352  print_liste_field_titre($arrayfields['m.type_mouvement']['label'], $_SERVER["PHP_SELF"], "m.type_mouvement", "", $param, '', $sortfield, $sortorder, 'center ');
1353 }
1354 if (!empty($arrayfields['m.value']['checked'])) {
1355  print_liste_field_titre($arrayfields['m.value']['label'], $_SERVER["PHP_SELF"], "m.value", "", $param, '', $sortfield, $sortorder, 'right ');
1356 }
1357 if (!empty($arrayfields['m.price']['checked'])) {
1358  print_liste_field_titre($arrayfields['m.price']['label'], $_SERVER["PHP_SELF"], "m.price", "", $param, '', $sortfield, $sortorder, 'right ');
1359 }
1360 
1361 // Extra fields
1362 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1363 
1364 // Hook fields
1365 $parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder, 'totalarray' => &$totalarray);
1366 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1367 print $hookmanager->resPrint;
1368 if (!empty($arrayfields['m.datec']['checked'])) {
1369  print_liste_field_titre($arrayfields['m.datec']['label'], $_SERVER["PHP_SELF"], "m.datec", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
1370 }
1371 if (!empty($arrayfields['m.tms']['checked'])) {
1372  print_liste_field_titre($arrayfields['m.tms']['label'], $_SERVER["PHP_SELF"], "m.tms", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
1373 }
1374 // Action column
1375 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1376  print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n";
1377  $totalarray['nbfield']++;
1378 }
1379 print '</tr>'."\n";
1380 
1381 
1382 $arrayofuniqueproduct = array();
1383 
1384 
1385 // Loop on record
1386 // --------------------------------------------------------------------
1387 $i = 0;
1388 $savnbfield = $totalarray['nbfield'];
1389 $totalarray = array();
1390 $totalarray['nbfield'] = 0;
1391 $imaxinloop = ($limit ? min($num, $limit) : $num);
1392 while ($i < $imaxinloop) {
1393  $obj = $db->fetch_object($resql);
1394  if (empty($obj)) {
1395  break; // Should not happen
1396  }
1397 
1398  $userstatic->id = $obj->fk_user_author;
1399  $userstatic->login = $obj->login;
1400  $userstatic->lastname = $obj->lastname;
1401  $userstatic->firstname = $obj->firstname;
1402  $userstatic->photo = $obj->photo;
1403  $userstatic->email = $obj->user_email;
1404  $userstatic->status = $obj->user_status;
1405 
1406  // Multilangs
1407  if (getDolGlobalInt('MAIN_MULTILANGS')) { // If multilang is enabled
1408  // TODO Use a cache
1409  $sql = "SELECT label";
1410  $sql .= " FROM ".MAIN_DB_PREFIX."product_lang";
1411  $sql .= " WHERE fk_product = ".((int) $obj->rowid);
1412  $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
1413  $sql .= " LIMIT 1";
1414 
1415  $result = $db->query($sql);
1416  if ($result) {
1417  $objtp = $db->fetch_object($result);
1418  if (!empty($objtp->label)) {
1419  $obj->produit = $objtp->label;
1420  }
1421  }
1422  }
1423 
1424  $productstatic->id = $obj->rowid;
1425  $productstatic->ref = $obj->product_ref;
1426  $productstatic->label = $obj->produit;
1427  $productstatic->type = $obj->type;
1428  $productstatic->entity = $obj->entity;
1429  $productstatic->status = $obj->tosell;
1430  $productstatic->status_buy = $obj->tobuy;
1431  $productstatic->status_batch = $obj->tobatch;
1432 
1433  $productlot->id = $obj->lotid;
1434  $productlot->batch = $obj->batch;
1435  $productlot->eatby = $obj->eatby;
1436  $productlot->sellby = $obj->sellby;
1437 
1438  $warehousestatic->id = $obj->entrepot_id;
1439  $warehousestatic->ref = $obj->warehouse_ref;
1440  $warehousestatic->label = $obj->warehouse_ref;
1441  $warehousestatic->lieu = $obj->lieu;
1442  $warehousestatic->fk_parent = $obj->fk_parent;
1443  $warehousestatic->statut = $obj->statut;
1444 
1445  $object->id = $obj->mid;
1446  $object->qty = $obj->qty;
1447  $object->label = $obj->label;
1448  $object->batch = $obj->batch;
1449  $object->warehouse_id = $obj->entrepot_id;
1450  $object->type = $obj->type_mouvement;
1451 
1452  $arrayofuniqueproduct[$obj->rowid] = $obj->produit;
1453  if (!empty($obj->fk_origin)) {
1454  $origin = $object->get_origin($obj->fk_origin, $obj->origintype);
1455  } else {
1456  $origin = '';
1457  }
1458 
1459  if ($mode == 'kanban') {
1460  if ($i == 0) {
1461  print '<tr class="trkanban"><td colspan="'.$savnbfield.'">';
1462  print '<div class="box-flex-container kanban">';
1463  }
1464  // Output Kanban
1465  $selected = -1;
1466  if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1467  $selected = 0;
1468  if (in_array($warehouse->id, $arrayofselected)) {
1469  $selected = 1;
1470  }
1471  }
1472  print $warehouse->getKanbanView('', array('selected' => $selected));
1473  if ($i == ($imaxinloop - 1)) {
1474  print '</div>';
1475  print '</td></tr>';
1476  }
1477  } else {
1478  // Show here line of result
1479  $j = 0;
1480  print '<tr data-rowid="'.$warehouse->id.'" class="oddeven">';
1481  // Action column
1482  if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1483  print '<td class="nowrap center">';
1484  if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1485  $selected = 0;
1486  if (in_array($obj->mid, $arrayofselected)) {
1487  $selected = 1;
1488  }
1489  print '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
1490  }
1491  print '</td>';
1492  if (!$i) {
1493  $totalarray['nbfield']++;
1494  }
1495  }
1496  // Id movement
1497  if (!empty($arrayfields['m.rowid']['checked'])) {
1498  print '<td class="nowraponall">';
1499  //print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
1500  print $object->getNomUrl(1);
1501  ;
1502  print '</td>'; // This is primary not movement id
1503  }
1504  if (!empty($arrayfields['m.datem']['checked'])) {
1505  // Date
1506  print '<td class="nowraponall center">'.dol_print_date($db->jdate($obj->datem), 'dayhour', 'tzuserrel').'</td>';
1507  }
1508  if (!empty($arrayfields['p.ref']['checked'])) {
1509  // Product ref
1510  print '<td class="nowraponall">';
1511  print $productstatic->getNomUrl(1, 'stock', 16);
1512  print "</td>\n";
1513  }
1514  if (!empty($arrayfields['p.label']['checked'])) {
1515  // Product label
1516  print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($productstatic->label).'">';
1517  print $productstatic->label;
1518  print "</td>\n";
1519  }
1520  if (!empty($arrayfields['m.batch']['checked'])) {
1521  print '<td class="center nowraponall">';
1522  if ($productlot->id > 0) {
1523  print $productlot->getNomUrl(1);
1524  } else {
1525  print $productlot->batch; // the id may not be defined if movement was entered when lot was not saved or if lot was removed after movement.
1526  }
1527  print '</td>';
1528  }
1529  if (!empty($arrayfields['pl.eatby']['checked'])) {
1530  print '<td class="center">'.dol_print_date($obj->eatby, 'day').'</td>';
1531  }
1532  if (!empty($arrayfields['pl.sellby']['checked'])) {
1533  print '<td class="center">'.dol_print_date($obj->sellby, 'day').'</td>';
1534  }
1535  // Warehouse
1536  if (!empty($arrayfields['e.ref']['checked'])) {
1537  print '<td class="tdoverflowmax100">';
1538  print $warehousestatic->getNomUrl(1);
1539  print "</td>\n";
1540  }
1541  // Author
1542  if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1543  print '<td class="tdoverflowmax100">';
1544  print $userstatic->getNomUrl(-1);
1545  print "</td>\n";
1546  }
1547  if (!empty($arrayfields['m.inventorycode']['checked'])) {
1548  // Inventory code
1549  print '<td><a href="'.$_SERVER["PHP_SELF"].'?search_inventorycode='.urlencode('^'.$obj->inventorycode.'$').'">'.dol_escape_htmltag($obj->inventorycode).'</a></td>';
1550  }
1551  if (!empty($arrayfields['m.label']['checked'])) {
1552  // Label of movement
1553  print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($obj->label).'">'.dol_escape_htmltag($obj->label).'</td>';
1554  }
1555  if (!empty($arrayfields['origin']['checked'])) {
1556  // Origin of movement
1557  print '<td class="nowraponall">'.$origin.'</td>';
1558  }
1559  if (!empty($arrayfields['m.fk_projet']['checked'])) {
1560  // fk_project
1561  print '<td>';
1562  if ($obj->fk_project != 0) {
1563  print $object->get_origin($obj->fk_project, 'project');
1564  }
1565  print '</td>';
1566  }
1567  if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1568  // Type of movement
1569  print '<td class="center">';
1570  print $object->getTypeMovement();
1571  print '</td>';
1572  }
1573  if (!empty($arrayfields['m.value']['checked'])) {
1574  // Qty
1575  print '<td class="right">';
1576  if ($obj->qty > 0) {
1577  print '<span class="stockmovemententry">';
1578  print '+';
1579  print $obj->qty;
1580  print '</span>';
1581  } else {
1582  print '<span class="stockmovementexit">';
1583  print $obj->qty;
1584  print '</span>';
1585  }
1586  print '</td>';
1587  }
1588  if (!empty($arrayfields['m.price']['checked'])) {
1589  // Price
1590  print '<td class="right">';
1591  if ($obj->price != 0) {
1592  print price($obj->price);
1593  }
1594  print '</td>';
1595  }
1596 
1597  // Extra fields
1598  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1599  // Fields from hook
1600  $parameters = array('arrayfields' => $arrayfields, 'object' => $object, 'obj' => $obj, 'i' => $i, 'totalarray' => &$totalarray);
1601  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1602  print $hookmanager->resPrint;
1603 
1604  // Action column
1605  if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1606  print '<td class="nowrap center">';
1607  if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1608  $selected = 0;
1609  if (in_array($obj->mid, $arrayofselected)) {
1610  $selected = 1;
1611  }
1612  print '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
1613  }
1614  print '</td>';
1615  if (!$i) {
1616  $totalarray['nbfield']++;
1617  }
1618  }
1619 
1620  print '</tr>'."\n";
1621  }
1622 
1623  $i++;
1624 }
1625 
1626 // If no record found
1627 if ($num == 0) {
1628  $colspan = 1;
1629  foreach ($arrayfields as $key => $val) {
1630  if (!empty($val['checked'])) {
1631  $colspan++;
1632  }
1633  }
1634  print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
1635 }
1636 
1637 $db->free($resql);
1638 
1639 $parameters = array('arrayfields' => $arrayfields, 'sql' => $sql);
1640 $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1641 print $hookmanager->resPrint;
1642 
1643 print '</table>'."\n";
1644 print '</div>'."\n";
1645 
1646 print '</form>'."\n";
1647 
1648 // Add number of product when there is a filter on period
1649 if (count($arrayofuniqueproduct) == 1 && !empty($year) && is_numeric($year)) {
1650  print "<br>";
1651 
1652  $productidselected = 0;
1653  foreach ($arrayofuniqueproduct as $key => $val) {
1654  $productidselected = $key;
1655  $productlabelselected = $val;
1656  }
1657  $datebefore = dol_get_first_day($year ? $year : dol_print_date(time(), "%Y"), $month ? $month : 1, true);
1658  $dateafter = dol_get_last_day($year ? $year : dol_print_date(time(), "%Y"), $month ? $month : 12, true);
1659  $balancebefore = $object->calculateBalanceForProductBefore($productidselected, $datebefore);
1660  $balanceafter = $object->calculateBalanceForProductBefore($productidselected, $dateafter);
1661 
1662  //print '<tr class="total"><td class="liste_total">';
1663  print $langs->trans("NbOfProductBeforePeriod", $productlabelselected, dol_print_date($datebefore, 'day', 'gmt'));
1664  //print '</td>';
1665  //print '<td class="liste_total right" colspan="6">';
1666  print ': '.$balancebefore;
1667  print "<br>\n";
1668  //print '</td></tr>';
1669  //print '<tr class="total"><td class="liste_total">';
1670  print $langs->trans("NbOfProductAfterPeriod", $productlabelselected, dol_print_date($dateafter, 'day', 'gmt'));
1671  //print '</td>';
1672  //print '<td class="liste_total right" colspan="6">';
1673  print ': '.$balanceafter;
1674  print "<br>\n";
1675  //print '</td></tr>';
1676 }
1677 
1678 if (in_array('builddoc', array_keys($arrayofmassactions)) && ($nbtotalofrecords === '' || $nbtotalofrecords)) {
1679  $hidegeneratedfilelistifempty = 1;
1680  if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) {
1681  $hidegeneratedfilelistifempty = 0;
1682  }
1683 
1684  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
1685  $formfile = new FormFile($db);
1686 
1687  // Show list of available documents
1688  $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
1689  $urlsource .= str_replace('&amp;', '&', $param);
1690 
1691  $filedir = $diroutputmassaction;
1692  $genallowed = $permissiontoread;
1693  $delallowed = $permissiontoadd;
1694 
1695  print $formfile->showdocuments('massfilesarea_stock', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty);
1696 }
1697 
1698 // End of page
1699 llxFooter();
1700 $db->close();
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:456
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:55
llxFooter()
Empty footer.
Definition: wrapper.php:69
Class to manage warehouses.
Class to manage standard extra fields.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
Class to manage stock movements.
Class to manage products or services.
Manage record for batch number management.
Class with list of lots and properties.
Class to manage projects.
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:50
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition: date.lib.php:595
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:614
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:63
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
stock_prepare_head($object)
Prepare array with list of tabs.
Definition: stock.lib.php:30