dolibarr  16.0.1
movement_card.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2020 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 Ferran Marcet <fmarcet@2byte.es>
7  * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  */
22 
29 require '../../main.inc.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
31 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
40 if (!empty($conf->project->enabled)) {
41  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
42  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
43 }
44 
45 // Load translation files required by the page
46 $langs->loadLangs(array('products', 'stocks', 'orders'));
47 if (!empty($conf->productbatch->enabled)) {
48  $langs->load("productbatch");
49 }
50 
51 // Security check
52 $result = restrictedArea($user, 'stock');
53 
54 $id = GETPOST('id', 'int');
55 $ref = GETPOST('ref', 'alpha');
56 $msid = GETPOST('msid', 'int');
57 $product_id = GETPOST("product_id", 'int');
58 $action = GETPOST('action', 'aZ09');
59 $cancel = GETPOST('cancel', 'alpha');
60 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'movementlist';
61 
62 $idproduct = GETPOST('idproduct', 'int');
63 $year = GETPOST("year", 'int');
64 $month = GETPOST("month", 'int');
65 $search_ref = GETPOST('search_ref', 'alpha');
66 $search_movement = GETPOST("search_movement", 'alpha');
67 $search_product_ref = trim(GETPOST("search_product_ref", 'alpha'));
68 $search_product = trim(GETPOST("search_product", 'alpha'));
69 $search_warehouse = trim(GETPOST("search_warehouse", 'alpha'));
70 $search_inventorycode = trim(GETPOST("search_inventorycode", 'alpha'));
71 $search_user = trim(GETPOST("search_user", 'alpha'));
72 $search_batch = trim(GETPOST("search_batch", 'alpha'));
73 $search_qty = trim(GETPOST("search_qty", 'alpha'));
74 $search_type_mouvement = GETPOST('search_type_mouvement', 'int');
75 
76 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
77 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
78 $sortfield = GETPOST('sortfield', 'aZ09comma');
79 $sortorder = GETPOST('sortorder', 'aZ09comma');
80 if (empty($page) || $page == -1) {
81  $page = 0;
82 } // If $page is not defined, or '' or -1
83 $offset = $limit * $page;
84 if (!$sortfield) {
85  $sortfield = "m.datem";
86 }
87 if (!$sortorder) {
88  $sortorder = "DESC";
89 }
90 
91 $pdluoid = GETPOST('pdluoid', 'int');
92 
93 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
94 $object = new MouvementStock($db);
95 $hookmanager->initHooks(array('movementlist'));
96 $extrafields = new ExtraFields($db);
97 $formfile = new FormFile($db);
98 
99 // fetch optionals attributes and labels
100 $extrafields->fetch_name_optionals_label($object->table_element);
101 
102 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
103 
104 $arrayfields = array(
105  'm.rowid'=>array('label'=>$langs->trans("Ref"), 'checked'=>1),
106  'm.datem'=>array('label'=>$langs->trans("Date"), 'checked'=>1),
107  'p.ref'=>array('label'=>$langs->trans("ProductRef"), 'checked'=>1, 'css'=>'maxwidth100'),
108  'p.label'=>array('label'=>$langs->trans("ProductLabel"), 'checked'=>1),
109  'm.batch'=>array('label'=>$langs->trans("BatchNumberShort"), 'checked'=>1, 'enabled'=>(!empty($conf->productbatch->enabled))),
110  'pl.eatby'=>array('label'=>$langs->trans("EatByDate"), 'checked'=>0, 'position'=>10, 'enabled'=>(!empty($conf->productbatch->enabled))),
111  'pl.sellby'=>array('label'=>$langs->trans("SellByDate"), 'checked'=>0, 'position'=>10, 'enabled'=>(!empty($conf->productbatch->enabled))),
112  'e.ref'=>array('label'=>$langs->trans("Warehouse"), 'checked'=>1, 'enabled'=>(!($id > 0))), // If we are on specific warehouse, we hide it
113  'm.fk_user_author'=>array('label'=>$langs->trans("Author"), 'checked'=>0),
114  'm.inventorycode'=>array('label'=>$langs->trans("InventoryCodeShort"), 'checked'=>1),
115  'm.label'=>array('label'=>$langs->trans("MovementLabel"), 'checked'=>1),
116  'm.type_mouvement'=>array('label'=>$langs->trans("TypeMovement"), 'checked'=>1),
117  'origin'=>array('label'=>$langs->trans("Origin"), 'checked'=>1),
118  'm.value'=>array('label'=>$langs->trans("Qty"), 'checked'=>1),
119  'm.price'=>array('label'=>$langs->trans("UnitPurchaseValue"), 'checked'=>0),
120  //'m.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
121  //'m.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500)
122 );
123 
124 $usercanread = (($user->rights->stock->mouvement->lire));
125 $usercancreate = (($user->rights->stock->mouvement->creer));
126 $usercandelete = (($user->rights->stock->mouvement->supprimer));
127 
128 
129 
130 /*
131  * Actions
132  */
133 
134 if (GETPOST('cancel', 'alpha')) {
135  $action = 'list'; $massaction = '';
136 }
137 if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
138  $massaction = '';
139 }
140 
141 $parameters = array();
142 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
143 if ($reshook < 0) {
144  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
145 }
146 
147 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
148 
149 // Do we click on purge search criteria ?
150 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
151  $year = '';
152  $month = '';
153  $search_ref = '';
154  $search_movement = "";
155  $search_type_mouvement = "";
156  $search_inventorycode = "";
157  $search_product_ref = "";
158  $search_product = "";
159  $search_warehouse = "";
160  $search_user = "";
161  $search_batch = "";
162  $search_qty = '';
163  $sall = "";
164  $toselect = array();
165  $search_array_options = array();
166 }
167 
168 // Correct stock
169 if ($action == "correct_stock") {
170  $product = new Product($db);
171  if (!empty($product_id)) {
172  $result = $product->fetch($product_id);
173  }
174 
175  $error = 0;
176 
177  if (empty($product_id)) {
178  $error++;
179  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
180  $action = 'correction';
181  }
182  if (!is_numeric(GETPOST("nbpiece"))) {
183  $error++;
184  setEventMessages($langs->trans("ErrorFieldMustBeANumeric", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
185  $action = 'correction';
186  }
187 
188  if (!$error) {
189  $origin_element = '';
190  $origin_id = null;
191 
192  if (GETPOST('projectid', 'int')) {
193  $origin_element = 'project';
194  $origin_id = GETPOST('projectid', 'int');
195  }
196 
197  if ($product->hasbatch()) {
198  $batch = GETPOST('batch_number', 'alpha');
199 
200  //$eatby=GETPOST('eatby');
201  //$sellby=GETPOST('sellby');
202  $eatby = dol_mktime(0, 0, 0, GETPOST('eatbymonth', 'int'), GETPOST('eatbyday', 'int'), GETPOST('eatbyyear', 'int'));
203  $sellby = dol_mktime(0, 0, 0, GETPOST('sellbymonth', 'int'), GETPOST('sellbyday', 'int'), GETPOST('sellbyyear', 'int'));
204 
205  $result = $product->correct_stock_batch(
206  $user,
207  $id,
208  GETPOST("nbpiece", 'int'),
209  GETPOST("mouvement", 'int'),
210  GETPOST("label", 'san_alpha'),
211  GETPOST('unitprice', 'alpha'),
212  $eatby,
213  $sellby,
214  $batch,
215  GETPOST('inventorycode', 'alpha'),
216  $origin_element,
217  $origin_id
218  ); // We do not change value of stock for a correction
219  } else {
220  $result = $product->correct_stock(
221  $user,
222  $id,
223  GETPOST("nbpiece", 'int'),
224  GETPOST("mouvement", 'alpha'),
225  GETPOST("label", 'san_alpha'),
226  GETPOST('unitprice', 'alpha'),
227  GETPOST('inventorycode', 'alpha'),
228  $origin_element,
229  $origin_id
230  ); // We do not change value of stock for a correction
231  }
232 
233  if ($result > 0) {
234  header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
235  exit;
236  } else {
237  $error++;
238  setEventMessages($product->error, $product->errors, 'errors');
239  $action = 'correction';
240  }
241  }
242 
243  if (!$error) {
244  $action = '';
245  }
246 }
247 
248 // Transfer stock from a warehouse to another warehouse
249 if ($action == "transfert_stock" && !$cancel) {
250  $product = new Product($db);
251  if (!empty($product_id)) {
252  $result = $product->fetch($product_id);
253  }
254 
255  if (!(GETPOST("id_entrepot_destination", 'int') > 0)) {
256  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
257  $error++;
258  $action = 'transfert';
259  }
260  if (empty($product_id)) {
261  $error++;
262  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
263  $action = 'transfert';
264  }
265  if (!GETPOST("nbpiece", 'int')) {
266  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
267  $error++;
268  $action = 'transfert';
269  }
270  if ($id == GETPOST("id_entrepot_destination", 'int')) {
271  setEventMessages($langs->trans("ErrorSrcAndTargetWarehouseMustDiffers"), null, 'errors');
272  $error++;
273  $action = 'transfert';
274  }
275 
276  if (!empty($conf->productbatch->enabled)) {
277  $product = new Product($db);
278  $result = $product->fetch($product_id);
279 
280  if ($product->hasbatch() && !GETPOST("batch_number", 'alpha')) {
281  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("batch_number")), null, 'errors');
282  $error++;
283  $action = 'transfert';
284  }
285  }
286 
287  if (!$error) {
288  if ($id) {
289  $object = new Entrepot($db);
290  $result = $object->fetch($id);
291 
292  $db->begin();
293 
294  $product->load_stock('novirtual'); // Load array product->stock_warehouse
295 
296  // Define value of products moved
297  $pricesrc = 0;
298  if (isset($product->pmp)) {
299  $pricesrc = $product->pmp;
300  }
301  $pricedest = $pricesrc;
302 
303  if ($product->hasbatch()) {
304  $pdluo = new Productbatch($db);
305 
306  if ($pdluoid > 0) {
307  $result = $pdluo->fetch($pdluoid);
308  if ($result) {
309  $srcwarehouseid = $pdluo->warehouseid;
310  $batch = $pdluo->batch;
311  $eatby = $pdluo->eatby;
312  $sellby = $pdluo->sellby;
313  } else {
314  setEventMessages($pdluo->error, $pdluo->errors, 'errors');
315  $error++;
316  }
317  } else {
318  $srcwarehouseid = $id;
319  $batch = GETPOST('batch_number', 'alpha');
320  $eatby = $d_eatby;
321  $sellby = $d_sellby;
322  }
323 
324  if (!$error) {
325  // Remove stock
326  $result1 = $product->correct_stock_batch(
327  $user,
328  $srcwarehouseid,
329  GETPOST("nbpiece", 'int'),
330  1,
331  GETPOST("label", 'san_alpha'),
332  $pricesrc,
333  $eatby,
334  $sellby,
335  $batch,
336  GETPOST('inventorycode', 'alpha')
337  );
338  // Add stock
339  $result2 = $product->correct_stock_batch(
340  $user,
341  GETPOST("id_entrepot_destination", 'int'),
342  GETPOST("nbpiece", 'int'),
343  0,
344  GETPOST("label", 'san_alpha'),
345  $pricedest,
346  $eatby,
347  $sellby,
348  $batch,
349  GETPOST('inventorycode', 'alpha')
350  );
351  }
352  } else {
353  // Remove stock
354  $result1 = $product->correct_stock(
355  $user,
356  $id,
357  GETPOST("nbpiece", 'int'),
358  1,
359  GETPOST("label", 'alpha'),
360  $pricesrc,
361  GETPOST('inventorycode', 'alpha')
362  );
363 
364  // Add stock
365  $result2 = $product->correct_stock(
366  $user,
367  GETPOST("id_entrepot_destination"),
368  GETPOST("nbpiece", 'int'),
369  0,
370  GETPOST("label", 'alpha'),
371  $pricedest,
372  GETPOST('inventorycode', 'alpha')
373  );
374  }
375  if (!$error && $result1 >= 0 && $result2 >= 0) {
376  $db->commit();
377 
378  if ($backtopage) {
379  header("Location: ".$backtopage);
380  exit;
381  } else {
382  header("Location: movement_list.php?id=".$object->id);
383  exit;
384  }
385  } else {
386  setEventMessages($product->error, $product->errors, 'errors');
387  $db->rollback();
388  $action = 'transfert';
389  }
390  }
391  }
392 }
393 
394 
395 /*
396  * Build document
397  */
398 // The builddoc action for object of a movement must be on the movement card
399 // Actions to build doc
400 $upload_dir = $conf->stock->dir_output."movement/";
401 $permissiontoadd = $user->rights->stock->creer;
402 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
403 
404 
405 if (empty($reshook) && $action != 'remove_file') {
406  $objectclass = 'MouvementStock';
407  $objectlabel = 'Movements';
408  $permissiontoread = $user->rights->stock->lire;
409  $permissiontodelete = $user->rights->stock->supprimer;
410  $uploaddir = $conf->stock->dir_output."/movement/";
411  include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
412 }
413 
414 
415 
416 /*
417  * View
418  */
419 
420 $productlot = new ProductLot($db);
421 $productstatic = new Product($db);
422 $warehousestatic = new Entrepot($db);
423 $movement = new MouvementStock($db);
424 $userstatic = new User($db);
425 $form = new Form($db);
426 $formother = new FormOther($db);
427 $formproduct = new FormProduct($db);
428 if (!empty($conf->project->enabled)) {
429  $formproject = new FormProjets($db);
430 }
431 
432 $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.tobatch, p.fk_product_type as type, p.entity,";
433 $sql .= " e.ref as warehouse_ref, e.rowid as entrepot_id, e.lieu,";
434 $sql .= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,";
435 $sql .= " m.batch, m.price,";
436 $sql .= " m.type_mouvement,";
437 $sql .= " pl.rowid as lotid, pl.eatby, pl.sellby,";
438 $sql .= " u.login, u.photo, u.lastname, u.firstname";
439 // Add fields from extrafields
440 if (!empty($extrafields->attributes[$object->table_element]['label'])) {
441  foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
442  $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
443  }
444 }
445 // Add fields from hooks
446 $parameters = array();
447 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
448 $sql .= $hookmanager->resPrint;
449 $sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
450 $sql .= " ".MAIN_DB_PREFIX."product as p,";
451 $sql .= " ".MAIN_DB_PREFIX."stock_mouvement as m";
452 if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
453  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (m.rowid = ef.fk_object)";
454 }
455 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON m.fk_user_author = u.rowid";
456 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON m.batch = pl.batch AND m.fk_product = pl.fk_product";
457 $sql .= " WHERE m.fk_product = p.rowid";
458 if ($msid > 0) {
459  $sql .= " AND m.rowid = ".((int) $msid);
460 }
461 $sql .= " AND m.fk_entrepot = e.rowid";
462 $sql .= " AND e.entity IN (".getEntity('stock').")";
463 if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
464  $sql .= " AND p.fk_product_type = 0";
465 }
466 if ($id > 0) {
467  $sql .= " AND e.rowid = ".((int) $id);
468 }
469 $sql .= dolSqlDateFilter('m.datem', 0, $month, $year);
470 if ($idproduct > 0) {
471  $sql .= " AND p.rowid = ".((int) $idproduct);
472 }
473 if (!empty($search_ref)) {
474  $sql .= natural_search('m.rowid', $search_ref, 1);
475 }
476 if (!empty($search_movement)) {
477  $sql .= natural_search('m.label', $search_movement);
478 }
479 if (!empty($search_inventorycode)) {
480  $sql .= natural_search('m.inventorycode', $search_inventorycode);
481 }
482 if (!empty($search_product_ref)) {
483  $sql .= natural_search('p.ref', $search_product_ref);
484 }
485 if (!empty($search_product)) {
486  $sql .= natural_search('p.label', $search_product);
487 }
488 if ($search_warehouse != '' && $search_warehouse != '-1') {
489  $sql .= natural_search('e.rowid', $search_warehouse, 2);
490 }
491 if (!empty($search_user)) {
492  $sql .= natural_search(array('u.lastname', 'u.firstname', 'u.login'), $search_user);
493 }
494 if (!empty($search_batch)) {
495  $sql .= natural_search('m.batch', $search_batch);
496 }
497 if ($search_qty != '') {
498  $sql .= natural_search('m.value', $search_qty, 1);
499 }
500 if ($search_type_mouvement != '' && $search_type_mouvement != '-1') {
501  $sql .= natural_search('m.type_mouvement', $search_type_mouvement, 2);
502 }
503 // Add where from extra fields
504 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
505 // Add where from hooks
506 $parameters = array();
507 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
508 $sql .= $hookmanager->resPrint;
509 $sql .= $db->order($sortfield, $sortorder);
510 
511 $nbtotalofrecords = '';
512 if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
513  $result = $db->query($sql);
514  $nbtotalofrecords = $db->num_rows($result);
515  if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
516  $page = 0;
517  $offset = 0;
518  }
519 }
520 
521 //print $sql;
522 
523 $resql = $db->query($sql);
524 
525 if ($resql) {
526  $product = new Product($db);
527  $object = new Entrepot($db);
528 
529  if ($idproduct > 0) {
530  $product->fetch($idproduct);
531  }
532  if ($id > 0 || $ref) {
533  $result = $object->fetch($id, $ref);
534  if ($result < 0) {
535  dol_print_error($db);
536  }
537  }
538 
539  $num = $db->num_rows($resql);
540 
541  $arrayofselected = is_array($toselect) ? $toselect : array();
542 
543 
544  $i = 0;
545  $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
546  if ($msid) {
547  $texte = $langs->trans('StockMovementForId', $msid);
548  } else {
549  $texte = $langs->trans("ListOfStockMovements");
550  if ($id) {
551  $texte .= ' ('.$langs->trans("ForThisWarehouse").')';
552  }
553  }
554  llxHeader("", $texte, $help_url);
555 
556  /*
557  * Show tab only if we ask a particular warehouse
558  */
559  if ($object->id > 0) {
560  $head = stock_prepare_head($object);
561 
562  print dol_get_fiche_head($head, 'movements', $langs->trans("Warehouse"), -1, 'stock');
563 
564 
565  $linkback = '<a href="'.DOL_URL_ROOT.'/product/stock/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
566 
567  $morehtmlref = '<div class="refidno">';
568  $morehtmlref .= $langs->trans("LocationSummary").' : '.$object->lieu;
569  $morehtmlref .= '</div>';
570 
571  $shownav = 1;
572  if ($user->socid && !in_array('stock', explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL))) {
573  $shownav = 0;
574  }
575 
576  dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref', 'ref', $morehtmlref);
577 
578 
579  print '<div class="fichecenter">';
580  print '<div class="fichehalfleft">';
581  print '<div class="underbanner clearboth"></div>';
582 
583  print '<table class="border centpercent">';
584 
585  print '<tr>';
586 
587  // Description
588  print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>'.dol_htmlentitiesbr($object->description).'</td></tr>';
589 
590  $calcproductsunique = $object->nb_different_products();
591  $calcproducts = $object->nb_products();
592 
593  // Total nb of different products
594  print '<tr><td>'.$langs->trans("NumberOfDifferentProducts").'</td><td>';
595  print empty($calcproductsunique['nb']) ? '0' : $calcproductsunique['nb'];
596  print "</td></tr>";
597 
598  // Nb of products
599  print '<tr><td>'.$langs->trans("NumberOfProducts").'</td><td>';
600  $valtoshow = price2num($calcproducts['nb'], 'MS');
601  print empty($valtoshow) ? '0' : $valtoshow;
602  print "</td></tr>";
603 
604  print '</table>';
605 
606  print '</div>';
607  print '<div class="fichehalfright">';
608  print '<div class="underbanner clearboth"></div>';
609 
610  print '<table class="border centpercent">';
611 
612  // Value
613  print '<tr><td class="titlefield">'.$langs->trans("EstimatedStockValueShort").'</td><td>';
614  print price((empty($calcproducts['value']) ? '0' : price2num($calcproducts['value'], 'MT')), 0, $langs, 0, -1, -1, $conf->currency);
615  print "</td></tr>";
616 
617  // Last movement
618  $sql = "SELECT MAX(m.datem) as datem";
619  $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
620  $sql .= " WHERE m.fk_entrepot = ".(int) $object->id;
621  $resqlbis = $db->query($sql);
622  if ($resqlbis) {
623  $obj = $db->fetch_object($resqlbis);
624  $lastmovementdate = $db->jdate($obj->datem);
625  } else {
626  dol_print_error($db);
627  }
628 
629  print '<tr><td>'.$langs->trans("LastMovement").'</td><td>';
630  if ($lastmovementdate) {
631  print dol_print_date($lastmovementdate, 'dayhour');
632  } else {
633  print $langs->trans("None");
634  }
635  print "</td></tr>";
636 
637  print "</table>";
638 
639  print '</div>';
640  print '</div>';
641 
642  print '<div class="clearboth"></div>';
643 
644  print dol_get_fiche_end();
645  }
646 
647 
648  /*
649  * Correct stock
650  */
651  if ($action == "correction") {
652  include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stockcorrection.tpl.php';
653  print '<br>';
654  }
655 
656  /*
657  * Transfer of units
658  */
659  if ($action == "transfert") {
660  include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stocktransfer.tpl.php';
661  print '<br>';
662  }
663 
664 
665  /*
666  * Action bar
667  */
668  if ((empty($action) || $action == 'list') && $id > 0) {
669  print "<div class=\"tabsAction\">\n";
670 
671  if ($user->rights->stock->mouvement->creer) {
672  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=correction">'.$langs->trans("CorrectStock").'</a>';
673  }
674 
675  if ($user->rights->stock->mouvement->creer) {
676  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=transfert">'.$langs->trans("TransferStock").'</a>';
677  }
678 
679  print '</div><br>';
680  }
681 
682  $param = '';
683  if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
684  $param .= '&contextpage='.urlencode($contextpage);
685  }
686  if ($limit > 0 && $limit != $conf->liste_limit) {
687  $param .= '&limit='.urlencode($limit);
688  }
689  if ($id > 0) {
690  $param .= '&id='.urlencode($id);
691  }
692  if ($search_movement) {
693  $param .= '&search_movement='.urlencode($search_movement);
694  }
695  if ($search_inventorycode) {
696  $param .= '&search_inventorycode='.urlencode($search_inventorycode);
697  }
698  if ($search_type_mouvement) {
699  $param .= '&search_type_mouvement='.urlencode($search_type_mouvement);
700  }
701  if ($search_product_ref) {
702  $param .= '&search_product_ref='.urlencode($search_product_ref);
703  }
704  if ($search_product) {
705  $param .= '&search_product='.urlencode($search_product);
706  }
707  if ($search_batch) {
708  $param .= '&search_batch='.urlencode($search_batch);
709  }
710  if ($search_warehouse > 0) {
711  $param .= '&search_warehouse='.urlencode($search_warehouse);
712  }
713  if ($search_user) {
714  $param .= '&search_user='.urlencode($search_user);
715  }
716  if ($idproduct > 0) {
717  $param .= '&idproduct='.urlencode($idproduct);
718  }
719  // Add $param from extra fields
720  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
721 
722  // List of mass actions available
723  $arrayofmassactions = array(
724  // 'presend'=>$langs->trans("SendByMail"),
725  // 'builddoc'=>$langs->trans("PDFMerge"),
726  );
727  //if ($user->rights->stock->supprimer) $arrayofmassactions['predelete']='<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
728  if (in_array($massaction, array('presend', 'predelete'))) {
729  $arrayofmassactions = array();
730  }
731  $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
732 
733  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
734  if ($optioncss != '') {
735  print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
736  }
737  print '<input type="hidden" name="token" value="'.newToken().'">';
738  print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
739  print '<input type="hidden" name="action" value="list">';
740  print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
741  print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
742  print '<input type="hidden" name="page" value="'.$page.'">';
743  print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
744  if ($id > 0) {
745  print '<input type="hidden" name="id" value="'.$id.'">';
746  }
747 
748  if ($id > 0) {
749  print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, '', 0, '', '', $limit);
750  } else {
751  print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, '', '', $limit);
752  }
753 
754  if ($sall) {
755  foreach ($fieldstosearchall as $key => $val) {
756  $fieldstosearchall[$key] = $langs->trans($val);
757  }
758  print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall).join(', ', $fieldstosearchall).'</div>';
759  }
760 
761  $moreforfilter = '';
762 
763  $parameters = array();
764  $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
765  if (empty($reshook)) {
766  $moreforfilter .= $hookmanager->resPrint;
767  } else {
768  $moreforfilter = $hookmanager->resPrint;
769  }
770 
771  if (!empty($moreforfilter)) {
772  print '<div class="liste_titre liste_titre_bydiv centpercent">';
773  print $moreforfilter;
774  print '</div>';
775  }
776 
777  $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
778  $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
779 
780  print '<div class="div-table-responsive">';
781  print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
782 
783  // Fields title search
784  print '<tr class="liste_titre_filter">';
785  if (!empty($arrayfields['m.rowid']['checked'])) {
786  // Ref
787  print '<td class="liste_titre left">';
788  print '<input class="flat maxwidth25" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
789  print '</td>';
790  }
791  if (!empty($arrayfields['m.datem']['checked'])) {
792  print '<td class="liste_titre nowraponall">';
793  print '<input class="flat" type="text" size="2" maxlength="2" placeholder="'.dol_escape_htmltag($langs->trans("Month")).'" name="month" value="'.$month.'">';
794  if (empty($conf->productbatch->enabled)) {
795  print '&nbsp;';
796  }
797  //else print '<br>';
798  $syear = $year ? $year : -1;
799  print '<input class="flat maxwidth50" type="text" maxlength="4" placeholder="'.dol_escape_htmltag($langs->trans("Year")).'" name="year" value="'.($syear > 0 ? $syear : '').'">';
800  //print $formother->selectyear($syear,'year',1, 20, 5);
801  print '</td>';
802  }
803  if (!empty($arrayfields['p.ref']['checked'])) {
804  // Product Ref
805  print '<td class="liste_titre left">';
806  print '<input class="flat maxwidth75" type="text" name="search_product_ref" value="'.dol_escape_htmltag($idproduct ? $product->ref : $search_product_ref).'">';
807  print '</td>';
808  }
809  if (!empty($arrayfields['p.label']['checked'])) {
810  // Product label
811  print '<td class="liste_titre left">';
812  print '<input class="flat maxwidth100" type="text" name="search_product" value="'.dol_escape_htmltag($idproduct ? $product->label : $search_product).'">';
813  print '</td>';
814  }
815  // Batch
816  if (!empty($arrayfields['m.batch']['checked'])) {
817  print '<td class="liste_titre center"><input class="flat maxwidth75" type="text" name="search_batch" value="'.dol_escape_htmltag($search_batch).'"></td>';
818  }
819  if (!empty($arrayfields['pl.eatby']['checked'])) {
820  print '<td class="liste_titre left">';
821  print '</td>';
822  }
823  if (!empty($arrayfields['pl.sellby']['checked'])) {
824  print '<td class="liste_titre left">';
825  print '</td>';
826  }
827  // Warehouse
828  if (!empty($arrayfields['e.ref']['checked'])) {
829  print '<td class="liste_titre maxwidthonsmartphone left">';
830  //print '<input class="flat" type="text" size="8" name="search_warehouse" value="'.($search_warehouse).'">';
831  print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
832  print '</td>';
833  }
834  if (!empty($arrayfields['m.fk_user_author']['checked'])) {
835  // Author
836  print '<td class="liste_titre left">';
837  print '<input class="flat" type="text" size="6" name="search_user" value="'.dol_escape_htmltag($search_user).'">';
838  print '</td>';
839  }
840  if (!empty($arrayfields['m.inventorycode']['checked'])) {
841  // Inventory code
842  print '<td class="liste_titre left">';
843  print '<input class="flat" type="text" size="4" name="search_inventorycode" value="'.dol_escape_htmltag($search_inventorycode).'">';
844  print '</td>';
845  }
846  if (!empty($arrayfields['m.label']['checked'])) {
847  // Label of movement
848  print '<td class="liste_titre left">';
849  print '<input class="flat" type="text" size="8" name="search_movement" value="'.dol_escape_htmltag($search_movement).'">';
850  print '</td>';
851  }
852  if (!empty($arrayfields['m.type_mouvement']['checked'])) {
853  // Type of movement
854  print '<td class="liste_titre center">';
855  //print '<input class="flat" type="text" size="3" name="search_type_mouvement" value="'.dol_escape_htmltag($search_type_mouvement).'">';
856  print '<select id="search_type_mouvement" name="search_type_mouvement" class="maxwidth150">';
857  print '<option value="" '.(($search_type_mouvement == "") ? 'selected="selected"' : '').'></option>';
858  print '<option value="0" '.(($search_type_mouvement == "0") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</option>';
859  print '<option value="1" '.(($search_type_mouvement == "1") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</option>';
860  print '<option value="2" '.(($search_type_mouvement == "2") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecrease').'</option>';
861  print '<option value="3" '.(($search_type_mouvement == "3") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncrease').'</option>';
862  print '</select>';
863  print ajax_combobox('search_type_mouvement');
864  // TODO: add new function $formentrepot->selectTypeOfMovement(...) like
865  // print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
866  print '</td>';
867  }
868  if (!empty($arrayfields['origin']['checked'])) {
869  // Origin of movement
870  print '<td class="liste_titre left">';
871  print '&nbsp; ';
872  print '</td>';
873  }
874  if (!empty($arrayfields['m.value']['checked'])) {
875  // Qty
876  print '<td class="liste_titre right">';
877  print '<input class="flat" type="text" size="4" name="search_qty" value="'.dol_escape_htmltag($search_qty).'">';
878  print '</td>';
879  }
880  if (!empty($arrayfields['m.price']['checked'])) {
881  // Price
882  print '<td class="liste_titre left">';
883  print '&nbsp; ';
884  print '</td>';
885  }
886 
887 
888  // Extra fields
889  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
890 
891  // Fields from hook
892  $parameters = array('arrayfields'=>$arrayfields);
893  $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
894  print $hookmanager->resPrint;
895  // Date creation
896  if (!empty($arrayfields['m.datec']['checked'])) {
897  print '<td class="liste_titre">';
898  print '</td>';
899  }
900  // Date modification
901  if (!empty($arrayfields['m.tms']['checked'])) {
902  print '<td class="liste_titre">';
903  print '</td>';
904  }
905  // Actions
906  print '<td class="liste_titre maxwidthsearch">';
907  $searchpicto = $form->showFilterAndCheckAddButtons(0);
908  print $searchpicto;
909  print '</td>';
910  print "</tr>\n";
911 
912  print '<tr class="liste_titre">';
913  if (!empty($arrayfields['m.rowid']['checked'])) {
914  print_liste_field_titre($arrayfields['m.rowid']['label'], $_SERVER["PHP_SELF"], 'm.rowid', '', $param, '', $sortfield, $sortorder);
915  }
916  if (!empty($arrayfields['m.datem']['checked'])) {
917  print_liste_field_titre($arrayfields['m.datem']['label'], $_SERVER["PHP_SELF"], 'm.datem', '', $param, '', $sortfield, $sortorder);
918  }
919  if (!empty($arrayfields['p.ref']['checked'])) {
920  print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder);
921  }
922  if (!empty($arrayfields['p.label']['checked'])) {
923  print_liste_field_titre($arrayfields['p.label']['label'], $_SERVER["PHP_SELF"], 'p.label', '', $param, '', $sortfield, $sortorder);
924  }
925  if (!empty($arrayfields['m.batch']['checked'])) {
926  print_liste_field_titre($arrayfields['m.batch']['label'], $_SERVER["PHP_SELF"], 'm.batch', '', $param, '', $sortfield, $sortorder, 'center ');
927  }
928  if (!empty($arrayfields['pl.eatby']['checked'])) {
929  print_liste_field_titre($arrayfields['pl.eatby']['label'], $_SERVER["PHP_SELF"], 'pl.eatby', '', $param, '', $sortfield, $sortorder, 'center ');
930  }
931  if (!empty($arrayfields['pl.sellby']['checked'])) {
932  print_liste_field_titre($arrayfields['pl.sellby']['label'], $_SERVER["PHP_SELF"], 'pl.sellby', '', $param, '', $sortfield, $sortorder, 'center ');
933  }
934  if (!empty($arrayfields['e.ref']['checked'])) {
935  // We are on a specific warehouse card, no filter on other should be possible
936  print_liste_field_titre($arrayfields['e.ref']['label'], $_SERVER["PHP_SELF"], "e.ref", "", $param, "", $sortfield, $sortorder);
937  }
938  if (!empty($arrayfields['m.fk_user_author']['checked'])) {
939  print_liste_field_titre($arrayfields['m.fk_user_author']['label'], $_SERVER["PHP_SELF"], "m.fk_user_author", "", $param, "", $sortfield, $sortorder);
940  }
941  if (!empty($arrayfields['m.inventorycode']['checked'])) {
942  print_liste_field_titre($arrayfields['m.inventorycode']['label'], $_SERVER["PHP_SELF"], "m.inventorycode", "", $param, "", $sortfield, $sortorder);
943  }
944  if (!empty($arrayfields['m.label']['checked'])) {
945  print_liste_field_titre($arrayfields['m.label']['label'], $_SERVER["PHP_SELF"], "m.label", "", $param, "", $sortfield, $sortorder);
946  }
947  if (!empty($arrayfields['m.type_mouvement']['checked'])) {
948  print_liste_field_titre($arrayfields['m.type_mouvement']['label'], $_SERVER["PHP_SELF"], "m.type_mouvement", "", $param, '', $sortfield, $sortorder, 'center ');
949  }
950  if (!empty($arrayfields['origin']['checked'])) {
951  print_liste_field_titre($arrayfields['origin']['label'], $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder);
952  }
953  if (!empty($arrayfields['m.value']['checked'])) {
954  print_liste_field_titre($arrayfields['m.value']['label'], $_SERVER["PHP_SELF"], "m.value", "", $param, '', $sortfield, $sortorder, 'right ');
955  }
956  if (!empty($arrayfields['m.price']['checked'])) {
957  print_liste_field_titre($arrayfields['m.price']['label'], $_SERVER["PHP_SELF"], "m.price", "", $param, '', $sortfield, $sortorder, 'right ');
958  }
959 
960  // Extra fields
961  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
962 
963  // Hook fields
964  $parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
965  $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
966  print $hookmanager->resPrint;
967  if (!empty($arrayfields['m.datec']['checked'])) {
968  print_liste_field_titre($arrayfields['p.datec']['label'], $_SERVER["PHP_SELF"], "p.datec", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
969  }
970  if (!empty($arrayfields['m.tms']['checked'])) {
971  print_liste_field_titre($arrayfields['p.tms']['label'], $_SERVER["PHP_SELF"], "p.tms", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
972  }
973  print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
974  print "</tr>\n";
975 
976 
977  $arrayofuniqueproduct = array();
978  while ($i < ($limit ? min($num, $limit) : $num)) {
979  $objp = $db->fetch_object($resql);
980 
981  $userstatic->id = $objp->fk_user_author;
982  $userstatic->login = $objp->login;
983  $userstatic->lastname = $objp->lastname;
984  $userstatic->firstname = $objp->firstname;
985  $userstatic->photo = $objp->photo;
986 
987  $productstatic->id = $objp->rowid;
988  $productstatic->ref = $objp->product_ref;
989  $productstatic->label = $objp->produit;
990  $productstatic->type = $objp->type;
991  $productstatic->entity = $objp->entity;
992  $productstatic->status_batch = $objp->tobatch;
993 
994  $productlot->id = $objp->lotid;
995  $productlot->batch = $objp->batch;
996  $productlot->eatby = $objp->eatby;
997  $productlot->sellby = $objp->sellby;
998 
999  $warehousestatic->id = $objp->entrepot_id;
1000  $warehousestatic->label = $objp->warehouse_ref;
1001  $warehousestatic->lieu = $objp->lieu;
1002 
1003  $arrayofuniqueproduct[$objp->rowid] = $objp->produit;
1004  if (!empty($objp->fk_origin)) {
1005  $origin = $movement->get_origin($objp->fk_origin, $objp->origintype);
1006  } else {
1007  $origin = '';
1008  }
1009 
1010  print '<tr class="oddeven">';
1011  // Id movement
1012  if (!empty($arrayfields['m.rowid']['checked'])) {
1013  // This is primary not movement id
1014  print '<td>'.$objp->mid.'</td>';
1015  }
1016  if (!empty($arrayfields['m.datem']['checked'])) {
1017  // Date
1018  print '<td>'.dol_print_date($db->jdate($objp->datem), 'dayhour').'</td>';
1019  }
1020  if (!empty($arrayfields['p.ref']['checked'])) {
1021  // Product ref
1022  print '<td class="nowraponall">';
1023  print $productstatic->getNomUrl(1, 'stock', 16);
1024  print "</td>\n";
1025  }
1026  if (!empty($arrayfields['p.label']['checked'])) {
1027  // Product label
1028  print '<td>';
1029  /*$productstatic->id=$objp->rowid;
1030  $productstatic->ref=$objp->produit;
1031  $productstatic->type=$objp->type;
1032  print $productstatic->getNomUrl(1,'',16);*/
1033  print $productstatic->label;
1034  print "</td>\n";
1035  }
1036  if (!empty($arrayfields['m.batch']['checked'])) {
1037  print '<td class="center nowraponall">';
1038  if ($productlot->id > 0) {
1039  print $productlot->getNomUrl(1);
1040  } else {
1041  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.
1042  }
1043  print '</td>';
1044  }
1045  if (!empty($arrayfields['pl.eatby']['checked'])) {
1046  print '<td class="center">'.dol_print_date($objp->eatby, 'day').'</td>';
1047  }
1048  if (!empty($arrayfields['pl.sellby']['checked'])) {
1049  print '<td class="center">'.dol_print_date($objp->sellby, 'day').'</td>';
1050  }
1051  // Warehouse
1052  if (!empty($arrayfields['e.ref']['checked'])) {
1053  print '<td>';
1054  print $warehousestatic->getNomUrl(1);
1055  print "</td>\n";
1056  }
1057  // Author
1058  if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1059  print '<td class="tdoverflowmax100">';
1060  print $userstatic->getNomUrl(-1);
1061  print "</td>\n";
1062  }
1063  if (!empty($arrayfields['m.inventorycode']['checked'])) {
1064  // Inventory code
1065  print '<td><a href="'
1066  .DOL_URL_ROOT.'/product/stock/movement_card.php?id='.urlencode($objp->entrepot_id)
1067  .'&search_inventorycode='.urlencode($objp->inventorycode)
1068  .'&search_type_mouvement='.urlencode($objp->type_mouvement)
1069  .'">'
1070  .$objp->inventorycode
1071  .'</a></td>';
1072  }
1073  if (!empty($arrayfields['m.label']['checked'])) {
1074  // Label of movement
1075  print '<td class="tdoverflowmax100aaa">'.$objp->label.'</td>';
1076  }
1077  if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1078  // Type of movement
1079  switch ($objp->type_mouvement) {
1080  case "0":
1081  print '<td class="center">'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</td>';
1082  break;
1083  case "1":
1084  print '<td class="center">'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</td>';
1085  break;
1086  case "2":
1087  print '<td class="center">'.$langs->trans('StockDecrease').'</td>';
1088  break;
1089  case "3":
1090  print '<td class="center">'.$langs->trans('StockIncrease').'</td>';
1091  break;
1092  }
1093  }
1094  if (!empty($arrayfields['origin']['checked'])) {
1095  // Origin of movement
1096  print '<td class="nowraponall">'.$origin.'</td>';
1097  }
1098  if (!empty($arrayfields['m.value']['checked'])) {
1099  // Qty
1100  print '<td class="right">';
1101  if ($objp->qt > 0) {
1102  print '+';
1103  }
1104  print $objp->qty;
1105  print '</td>';
1106  }
1107  if (!empty($arrayfields['m.price']['checked'])) {
1108  // Price
1109  print '<td class="right">';
1110  if ($objp->price != 0) {
1111  print price($objp->price);
1112  }
1113  print '</td>';
1114  }
1115  // Action column
1116  print '<td class="nowrap center">';
1117  if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1118  $selected = 0;
1119  if (in_array($obj->rowid, $arrayofselected)) {
1120  $selected = 1;
1121  }
1122  print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
1123  }
1124  print '</td>';
1125  if (!$i) {
1126  $totalarray['nbfield']++;
1127  }
1128 
1129  print "</tr>\n";
1130  $i++;
1131  }
1132  $db->free($resql);
1133 
1134  print "</table>";
1135  print '</div>';
1136  print "</form>";
1137 
1138  // Add number of product when there is a filter on period
1139  if (count($arrayofuniqueproduct) == 1 && is_numeric($year)) {
1140  print "<br>";
1141 
1142  $productidselected = 0;
1143  foreach ($arrayofuniqueproduct as $key => $val) {
1144  $productidselected = $key;
1145  $productlabelselected = $val;
1146  }
1147  $datebefore = dol_get_first_day($year ? $year : strftime("%Y", time()), $month ? $month : 1, true);
1148  $dateafter = dol_get_last_day($year ? $year : strftime("%Y", time()), $month ? $month : 12, true);
1149  $balancebefore = $movement->calculateBalanceForProductBefore($productidselected, $datebefore);
1150  $balanceafter = $movement->calculateBalanceForProductBefore($productidselected, $dateafter);
1151 
1152  //print '<tr class="total"><td class="liste_total">';
1153  print $langs->trans("NbOfProductBeforePeriod", $productlabelselected, dol_print_date($datebefore, 'day', 'gmt'));
1154  //print '</td>';
1155  //print '<td class="liste_total right" colspan="6">';
1156  print ': '.$balancebefore;
1157  print "<br>\n";
1158  //print '</td></tr>';
1159  //print '<tr class="total"><td class="liste_total">';
1160  print $langs->trans("NbOfProductAfterPeriod", $productlabelselected, dol_print_date($dateafter, 'day', 'gmt'));
1161  //print '</td>';
1162  //print '<td class="liste_total right" colspan="6">';
1163  print ': '.$balanceafter;
1164  print "<br>\n";
1165  //print '</td></tr>';
1166  }
1167 } else {
1168  dol_print_error($db);
1169 }
1170 
1171 
1172 
1173 /*
1174  * Generated documents
1175  */
1176 //Area for doc and last events of warehouse are stored on the main card of warehouse
1177 $modulepart = 'movement';
1178 
1179 if ($action != 'create' && $action != 'edit' && $action != 'delete' && $id > 0) {
1180  print '<br>';
1181  print '<div class="fichecenter"><div class="fichehalfleft">';
1182  print '<a name="builddoc"></a>'; // ancre
1183 
1184  // Documents
1185  $objectref = dol_sanitizeFileName($object->ref);
1186  // Add inventorycode & type_mouvement to filename of the pdf
1187  if (!empty($search_inventorycode)) {
1188  $objectref .= "_".$id."_".$search_inventorycode;
1189  }
1190  if ($search_type_mouvement) {
1191  $objectref .= "_".$search_type_mouvement;
1192  }
1193  $relativepath = $comref.'/'.$objectref.'.pdf';
1194  $filedir = $conf->stock->dir_output.'/movement/'.$objectref;
1195 
1196  $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id."&search_inventorycode=".$search_inventorycode."&search_type_mouvement=$search_type_mouvement";
1197  $genallowed = $usercanread;
1198  $delallowed = $usercancreate;
1199 
1200  $genallowed = $user->rights->stock->lire;
1201  $delallowed = $user->rights->stock->creer;
1202 
1203  print $formfile->showdocuments($modulepart, $objectref, $filedir, $urlsource, $genallowed, $delallowed, '', 0, 0, 0, 28, 0, '', 0, '', $object->default_lang, '', $object);
1204  $somethingshown = $formfile->numoffiles;
1205 
1206  print '</div><div class="fichehalfright">';
1207 
1208  $MAXEVENT = 10;
1209 
1210  $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/product/agenda.php?id='.$object->id);
1211 
1212  // List of actions on element
1213  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
1214  $formactions = new FormActions($db);
1215  $somethingshown = $formactions->showactions($object, 'mouvement', 0, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for product
1216 
1217  print '</div></div>';
1218 }
1219 
1220 
1221 // End of page
1222 llxFooter();
1223 $db->close();
dolSqlDateFilter($datefield, $day_date, $month_date, $year_date, $excludefirstand=0, $gm=false)
Generate a SQL string to make a filter into a range (for second of date until last second of date)...
Definition: date.lib.php:334
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Class to manage stock movements.
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action== 'set') elseif($action== 'specimen') elseif($action== 'setmodel') elseif($action== 'del') elseif($action== 'setdoc') $formactions
View.
if($cancel &&!$id) if($action== 'add'&&!$cancel) if($action== 'delete') if($id) $form
Actions.
Definition: card.php:142
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm= 'auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
Class to manage building of HTML components.
dolGetButtonTitle($label, $helpText= '', $iconClass= 'fa fa-file', $url= '', $id= '', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
Class to manage products or services.
Class to manage Dolibarr users.
Definition: user.class.php:44
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOCSRFCHECK')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:59
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...
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition: date.lib.php:551
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save"&&empty($cancel)) $help_url
View.
Definition: agenda.php:116
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...
Class with static methods for building HTML components related to products Only components common to ...
Class to manage standard extra fields.
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
print_barre_liste($titre, $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.
Class to manage generation of HTML components Only common components must be here.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form...
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
stock_prepare_head($object)
Prepare array with list of tabs.
Definition: stock.lib.php:30
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
Class to manage building of HTML components.
Classe permettant la generation de composants html autre Only common components are here...
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...
dol_sanitizeFileName($str, $newstr= '_', $unaccent=1)
Clean a string to use it as a file name.
Class to offer components to list and upload files.
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete= 'resolve', $idforemptyvalue= '-1')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:429
restrictedArea($user, $features, $objectid=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.
if(isModEnabled('facture')&&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur')&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)&&$user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice')&&$user->rights->supplier_invoice->lire)) if(isModEnabled('don')&&!empty($user->rights->don->lire)) if(isModEnabled('tax')&&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture')&&isModEnabled('commande')&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
dol_get_fiche_head($links=array(), $active= '', $title= '', $notab=0, $picto= '', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limittoshow=0, $moretabssuffix= '')
Show tabs of a record.
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition: date.lib.php:570
Manage record for batch number management.
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_banner_tab($object, $paramid, $morehtml= '', $shownav=1, $fieldid= 'rowid', $fieldref= 'ref', $morehtmlref= '', $moreparam= '', $nodbprefix=0, $morehtmlleft= '', $morehtmlstatus= '', $onlybanner=0, $morehtmlright= '')
Show tab footer of a card.
llxFooter()
Empty footer.
Definition: wrapper.php:73
Class to manage warehouses.