dolibarr  16.0.5
massstockmove.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2013-2021 Laurent Destaileur <ely@users.sourceforge.net>
3  * Copyright (C) 2014 Regis Houssin <regis.houssin@inodbox.com>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
26 require '../../main.inc.php';
27 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
28 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
31 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/modules/import/import_csv.modules.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/lib/import.lib.php';
36 
37 $confirm = GETPOST('confirm', 'alpha');
38 $filetoimport = GETPOST('filetoimport');
39 
40 // Load translation files required by the page
41 $langs->loadLangs(array('products', 'stocks', 'orders', 'productbatch'));
42 
43 //init Hook
44 $hookmanager->initHooks(array('massstockmove'));
45 
46 // Security check
47 if ($user->socid) {
48  $socid = $user->socid;
49 }
50 $result = restrictedArea($user, 'produit|service');
51 
52 //checks if a product has been ordered
53 
54 $action = GETPOST('action', 'aZ09');
55 $id_product = GETPOST('productid', 'int');
56 $id_sw = GETPOST('id_sw', 'int');
57 $id_tw = GETPOST('id_tw', 'int');
58 $batch = GETPOST('batch');
59 $qty = GETPOST('qty');
60 $idline = GETPOST('idline');
61 
62 $sortfield = GETPOST('sortfield', 'aZ09comma');
63 $sortorder = GETPOST('sortorder', 'aZ09comma');
64 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
65 if (empty($page) || $page == -1) {
66  $page = 0;
67 } // If $page is not defined, or '' or -1
68 
69 if (!$sortfield) {
70  $sortfield = 'p.ref';
71 }
72 
73 if (!$sortorder) {
74  $sortorder = 'ASC';
75 }
76 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
77 $offset = $limit * $page;
78 
79 $listofdata = array();
80 if (!empty($_SESSION['massstockmove'])) {
81  $listofdata = json_decode($_SESSION['massstockmove'], true);
82 }
83 
84 
85 /*
86  * Actions
87  */
88 
89 if ($action == 'addline' && !empty($user->rights->stock->mouvement->creer)) {
90  if (!($id_product > 0)) {
91  $error++;
92  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
93  }
94  if (!($id_sw > 0)) {
95  $error++;
96  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseSource")), null, 'errors');
97  }
98  if (!($id_tw > 0)) {
99  $error++;
100  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseTarget")), null, 'errors');
101  }
102  if ($id_sw > 0 && $id_tw == $id_sw) {
103  $error++;
104  $langs->load("errors");
105  setEventMessages($langs->trans("ErrorWarehouseMustDiffers"), null, 'errors');
106  }
107  if (!$qty) {
108  $error++;
109  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Qty")), null, 'errors');
110  }
111 
112  // Check a batch number is provided if product need it
113  if (!$error) {
114  $producttmp = new Product($db);
115  $producttmp->fetch($id_product);
116  if ($producttmp->hasbatch()) {
117  if (empty($batch)) {
118  $error++;
119  $langs->load("errors");
120  setEventMessages($langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData", $producttmp->ref), null, 'errors');
121  }
122  }
123  }
124 
125  // TODO Check qty is ok for stock move. Note qty may not be enough yet, but we make a check now to report a warning.
126  // What is more important is to have qty when doing action 'createmovements'
127  if (!$error) {
128  // Warning, don't forget lines already added into the $_SESSION['massstockmove']
129  if ($producttmp->hasbatch()) {
130  } else {
131  }
132  }
133 
134  if (!$error) {
135  if (count(array_keys($listofdata)) > 0) {
136  $id = max(array_keys($listofdata)) + 1;
137  } else {
138  $id = 1;
139  }
140  $listofdata[$id] = array('id'=>$id, 'id_product'=>$id_product, 'qty'=>$qty, 'id_sw'=>$id_sw, 'id_tw'=>$id_tw, 'batch'=>$batch);
141  $_SESSION['massstockmove'] = json_encode($listofdata);
142 
143  //unset($id_sw);
144  //unset($id_tw);
145  unset($id_product);
146  unset($batch);
147  unset($qty);
148  }
149 }
150 
151 if ($action == 'delline' && $idline != '' && !empty($user->rights->stock->mouvement->creer)) {
152  if (!empty($listofdata[$idline])) {
153  unset($listofdata[$idline]);
154  }
155  if (count($listofdata) > 0) {
156  $_SESSION['massstockmove'] = json_encode($listofdata);
157  } else {
158  unset($_SESSION['massstockmove']);
159  }
160 }
161 
162 if ($action == 'createmovements' && !empty($user->rights->stock->mouvement->creer)) {
163  $error = 0;
164 
165  if (!GETPOST("label")) {
166  $error++;
167  setEventMessages($langs->trans("ErrorFieldRequired"), $langs->transnoentitiesnoconv("MovementLabel"), null, 'errors');
168  }
169 
170  $db->begin();
171 
172  if (!$error) {
173  $product = new Product($db);
174 
175  foreach ($listofdata as $key => $val) { // Loop on each movement to do
176  $id = $val['id'];
177  $id_product = $val['id_product'];
178  $id_sw = $val['id_sw'];
179  $id_tw = $val['id_tw'];
180  $qty = price2num($val['qty']);
181  $batch = $val['batch'];
182  $dlc = -1; // They are loaded later from serial
183  $dluo = -1; // They are loaded later from serial
184 
185  if (!$error && $id_sw <> $id_tw && is_numeric($qty) && $id_product) {
186  $result = $product->fetch($id_product);
187 
188  $product->load_stock('novirtual'); // Load array product->stock_warehouse
189 
190  // Define value of products moved
191  $pricesrc = 0;
192  if (!empty($product->pmp)) {
193  $pricesrc = $product->pmp;
194  }
195  $pricedest = $pricesrc;
196 
197  //print 'price src='.$pricesrc.', price dest='.$pricedest;exit;
198 
199  if (empty($conf->productbatch->enabled) || !$product->hasbatch()) { // If product does not need lot/serial
200  // Remove stock
201  $result1 = $product->correct_stock(
202  $user,
203  $id_sw,
204  $qty,
205  1,
206  GETPOST("label"),
207  $pricesrc,
208  GETPOST("codemove")
209  );
210  if ($result1 < 0) {
211  $error++;
212  setEventMessages($product->error, $product->errors, 'errors');
213  }
214 
215  // Add stock
216  $result2 = $product->correct_stock(
217  $user,
218  $id_tw,
219  $qty,
220  0,
221  GETPOST("label"),
222  $pricedest,
223  GETPOST("codemove")
224  );
225  if ($result2 < 0) {
226  $error++;
227  setEventMessages($product->error, $product->errors, 'errors');
228  }
229  } else {
230  $arraybatchinfo = $product->loadBatchInfo($batch);
231  if (count($arraybatchinfo) > 0) {
232  $firstrecord = array_shift($arraybatchinfo);
233  $dlc = $firstrecord['eatby'];
234  $dluo = $firstrecord['sellby'];
235  //var_dump($batch);
236  //var_dump($arraybatchinfo);
237  //var_dump($firstrecord);
238  //var_dump($dlc);
239  //var_dump($dluo); exit;
240  } else {
241  $dlc = '';
242  $dluo = '';
243  }
244 
245  // Remove stock
246  $result1 = $product->correct_stock_batch(
247  $user,
248  $id_sw,
249  $qty,
250  1,
251  GETPOST("label"),
252  $pricesrc,
253  $dlc,
254  $dluo,
255  $batch,
256  GETPOST("codemove")
257  );
258  if ($result1 < 0) {
259  $error++;
260  setEventMessages($product->error, $product->errors, 'errors');
261  }
262 
263  // Add stock
264  $result2 = $product->correct_stock_batch(
265  $user,
266  $id_tw,
267  $qty,
268  0,
269  GETPOST("label"),
270  $pricedest,
271  $dlc,
272  $dluo,
273  $batch,
274  GETPOST("codemove")
275  );
276  if ($result2 < 0) {
277  $error++;
278  setEventMessages($product->error, $product->errors, 'errors');
279  }
280  }
281  } else {
282  // dol_print_error('',"Bad value saved into sessions");
283  $error++;
284  }
285  }
286  }
287 
288  if (!$error) {
289  unset($_SESSION['massstockmove']);
290 
291  $db->commit();
292  setEventMessages($langs->trans("StockMovementRecorded"), null, 'mesgs');
293  header("Location: ".DOL_URL_ROOT.'/product/stock/index.php'); // Redirect to avoid pb when using back
294  exit;
295  } else {
296  $db->rollback();
297  setEventMessages($langs->trans("Error"), null, 'errors');
298  }
299 }
300 
301 if ($action == 'importCSV' && !empty($user->rights->stock->mouvement->creer)) {
302  dol_mkdir($conf->stock->dir_temp);
303  $nowyearmonth = dol_print_date(dol_now(), '%Y%m%d%H%M%S');
304 
305  $fullpath = $conf->stock->dir_temp."/".$user->id.'-csvfiletotimport.csv';
306  if (dol_move_uploaded_file($_FILES['userfile']['tmp_name'], $fullpath, 1) > 0) {
307  dol_syslog("File ".$fullpath." was added for import");
308  } else {
309  $error++;
310  $langs->load("errors");
311  setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
312  }
313 
314  if (!$error) {
315  $importcsv = new ImportCsv($db, 'massstocklist');
316  //print $importcsv->separator;
317 
318  $nblinesrecord = $importcsv->import_get_nb_of_lines($fullpath)-1;
319  $importcsv->import_open_file($fullpath);
320  $labelsrecord = $importcsv->import_read_record();
321 
322  if ($nblinesrecord < 1) {
323  setEventMessages($langs->trans("BadNumberOfLinesMustHaveAtLeastOneLinePlusTitle"), null, 'errors');
324  } else {
325  $i=0;
326  $data = array();
327  $productstatic = new Product($db);
328  $warehousestatics = new Entrepot($db);
329  $warehousestatict = new Entrepot($db);
330  while (($i < $nblinesrecord) && !$error) {
331  $data[] = $importcsv->import_read_record();
332  if (count($data[$i]) == 1) {
333  // Only 1 empty line
334  unset($data[$i]);
335  $i++;
336  continue;
337  }
338  //var_dump($data);
339  $tmp_id_sw = $data[$i][0]['val'];
340  $tmp_id_tw = $data[$i][1]['val'];
341  $tmp_id_product = $data[$i][2]['val'];
342  $tmp_qty = $data[$i][3]['val'];
343  $tmp_batch = $data[$i][4]['val'];
344 
345  if (!is_numeric($tmp_id_product)) {
346  $result = fetchref($productstatic, $tmp_id_product);
347  $tmp_id_product = $result;
348  $data[$i][2]['val'] = $result;
349  }
350  if (!($tmp_id_product > 0)) {
351  $error++;
352  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
353  }
354 
355  if (!is_numeric($tmp_id_sw)) {
356  $result = fetchref($warehousestatics, $tmp_id_sw);
357  $tmp_id_sw = $result;
358  $data[$i][0]['val'] = $result;
359  }
360  if (!($tmp_id_sw > 0)) {
361  $error++;
362  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseSource")), null, 'errors');
363  }
364 
365  if (!is_numeric($tmp_id_tw)) {
366  $result = fetchref($warehousestatict, $tmp_id_tw);
367  $tmp_id_tw = $result;
368  $data[$i][1]['val'] = $result;
369  }
370  if (!($tmp_id_tw > 0)) {
371  $error++;
372  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseTarget")), null, 'errors');
373  }
374 
375  if ($tmp_id_sw > 0 && $tmp_id_tw == $tmp_id_sw) {
376  $error++;
377  $langs->load("errors");
378  setEventMessages($langs->trans("ErrorWarehouseMustDiffers"), null, 'errors');
379  }
380  if (!$tmp_qty) {
381  $error++;
382  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Qty")), null, 'errors');
383  }
384 
385  // Check a batch number is provided if product need it
386  if (!$error) {
387  $producttmp = new Product($db);
388  $producttmp->fetch($tmp_id_product);
389  if ($producttmp->hasbatch()) {
390  if (empty($tmp_batch)) {
391  $error++;
392  $langs->load("errors");
393  setEventMessages($langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData", $producttmp->ref), null, 'errors');
394  }
395  }
396  }
397 
398  $i++;
399  }
400 
401  if (!$error) {
402  foreach ($data as $key => $value) {
403  if (count(array_keys($listofdata)) > 0) {
404  $id = max(array_keys($listofdata)) + 1;
405  } else {
406  $id = 1;
407  }
408  $tmp_id_sw = $data[$key][0]['val'];
409  $tmp_id_tw = $data[$key][1]['val'];
410  $tmp_id_product = $data[$key][2]['val'];
411  $tmp_qty = $data[$key][3]['val'];
412  $tmp_batch = $data[$key][4]['val'];
413  $listofdata[$key] = array('id'=>$key, 'id_sw'=>$tmp_id_sw, 'id_tw'=>$tmp_id_tw, 'id_product'=>$tmp_id_product, 'qty'=>$tmp_qty, 'batch'=>$tmp_batch);
414  }
415  }
416  }
417  }
418 
419  $_SESSION['massstockmove'] = json_encode($listofdata);
420 }
421 
422 if ($action == 'confirm_deletefile' && $confirm == 'yes') {
423  $langs->load("other");
424 
425  $param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
426  if ($excludefirstline) {
427  $param .= '&excludefirstline='.urlencode($excludefirstline);
428  }
429  if ($endatlinenb) {
430  $param .= '&endatlinenb='.urlencode($endatlinenb);
431  }
432 
433  $file = $conf->stock->dir_temp.'/'.GETPOST('urlfile'); // Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
434  $ret = dol_delete_file($file);
435  if ($ret) {
436  setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
437  } else {
438  setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
439  }
440  Header('Location: '.$_SERVER["PHP_SELF"]);
441  exit;
442 }
443 
444 
445 /*
446  * View
447  */
448 
449 $now = dol_now();
450 $error = 0;
451 
452 $form = new Form($db);
453 $formproduct = new FormProduct($db);
454 $productstatic = new Product($db);
455 $warehousestatics = new Entrepot($db);
456 $warehousestatict = new Entrepot($db);
457 
458 $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks|DE:Modul_Bestände';
459 
460 $title = $langs->trans('MassMovement');
461 
462 llxHeader('', $title, $help_url);
463 
464 print load_fiche_titre($langs->trans("MassStockTransferShort"), '', 'stock');
465 
466 $titletoadd = $langs->trans("Select");
467 $buttonrecord = $langs->trans("RecordMovement");
468 $titletoaddnoent = $langs->transnoentitiesnoconv("Select");
469 $buttonrecordnoent = $langs->transnoentitiesnoconv("RecordMovement");
470 print '<span class="opacitymedium">'.$langs->trans("SelectProductInAndOutWareHouse", $titletoaddnoent, $buttonrecordnoent).'</span><br>';
471 
472 print '<br>';
473 
474 // Form to upload a file
475 print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" METHOD="POST">';
476 print '<input type="hidden" name="token" value="'.newToken().'">';
477 print '<input type="hidden" name="action" value="importCSV">';
478 print '<span class="opacitymedium">';
479 print $langs->trans("or").' ';
480 $importcsv = new ImportCsv($db, 'massstocklist');
481 print $form->textwithpicto($langs->trans('SelectAStockMovementFileToImport'), $langs->transnoentitiesnoconv("InfoTemplateImport", $importcsv->separator));
482 print '</span>';
483 
484 $maxfilesizearray = getMaxFileSizeArray();
485 $maxmin = $maxfilesizearray['maxmin'];
486 if ($maxmin > 0) {
487  print '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
488 }
489 print '<input type="file" name="userfile" size="20" maxlength="80"> &nbsp; &nbsp; ';
490 $out = (empty($conf->global->MAIN_UPLOAD_DOC) ? ' disabled' : '');
491 print '<input type="submit" class="button small" value="'.$langs->trans("ImportFromCSV").'"'.$out.' name="sendit">';
492 $out = '';
493 if (!empty($conf->global->MAIN_UPLOAD_DOC)) {
494  $max = $conf->global->MAIN_UPLOAD_DOC; // In Kb
495  $maxphp = @ini_get('upload_max_filesize'); // In unknown
496  if (preg_match('/k$/i', $maxphp)) {
497  $maxphp = preg_replace('/k$/i', '', $maxphp);
498  $maxphp = $maxphp * 1;
499  }
500  if (preg_match('/m$/i', $maxphp)) {
501  $maxphp = preg_replace('/m$/i', '', $maxphp);
502  $maxphp = $maxphp * 1024;
503  }
504  if (preg_match('/g$/i', $maxphp)) {
505  $maxphp = preg_replace('/g$/i', '', $maxphp);
506  $maxphp = $maxphp * 1024 * 1024;
507  }
508  if (preg_match('/t$/i', $maxphp)) {
509  $maxphp = preg_replace('/t$/i', '', $maxphp);
510  $maxphp = $maxphp * 1024 * 1024 * 1024;
511  }
512  $maxphp2 = @ini_get('post_max_size'); // In unknown
513  if (preg_match('/k$/i', $maxphp2)) {
514  $maxphp2 = preg_replace('/k$/i', '', $maxphp2);
515  $maxphp2 = $maxphp2 * 1;
516  }
517  if (preg_match('/m$/i', $maxphp2)) {
518  $maxphp2 = preg_replace('/m$/i', '', $maxphp2);
519  $maxphp2 = $maxphp2 * 1024;
520  }
521  if (preg_match('/g$/i', $maxphp2)) {
522  $maxphp2 = preg_replace('/g$/i', '', $maxphp2);
523  $maxphp2 = $maxphp2 * 1024 * 1024;
524  }
525  if (preg_match('/t$/i', $maxphp2)) {
526  $maxphp2 = preg_replace('/t$/i', '', $maxphp2);
527  $maxphp2 = $maxphp2 * 1024 * 1024 * 1024;
528  }
529  // Now $max and $maxphp and $maxphp2 are in Kb
530  $maxmin = $max;
531  $maxphptoshow = $maxphptoshowparam = '';
532  if ($maxphp > 0) {
533  $maxmin = min($max, $maxphp);
534  $maxphptoshow = $maxphp;
535  $maxphptoshowparam = 'upload_max_filesize';
536  }
537  if ($maxphp2 > 0) {
538  $maxmin = min($max, $maxphp2);
539  if ($maxphp2 < $maxphp) {
540  $maxphptoshow = $maxphp2;
541  $maxphptoshowparam = 'post_max_size';
542  }
543  }
544 
545  $langs->load('other');
546  $out .= ' ';
547  $out .= info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow), 1);
548 } else {
549  $out .= ' ('.$langs->trans("UploadDisabled").')';
550 }
551 print $out;
552 
553 print '</form>';
554 
555 print '<br><br>';
556 
557 // Form to add a line
558 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">';
559 print '<input type="hidden" name="token" value="'.newToken().'">';
560 print '<input type="hidden" name="action" value="addline">';
561 
562 
563 print '<div class="div-table-responsive-no-min">';
564 print '<table class="liste centpercent">';
565 
566 $param = '';
567 
568 print '<tr class="liste_titre">';
569 print getTitleFieldOfList($langs->trans('WarehouseSource'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
570 print getTitleFieldOfList($langs->trans('WarehouseTarget'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
571 print getTitleFieldOfList($langs->trans('ProductRef'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
572 if (isModEnabled('productbatch')) {
573  print getTitleFieldOfList($langs->trans('Batch'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
574 }
575 print getTitleFieldOfList($langs->trans('Qty'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'center tagtd maxwidthonsmartphone ');
576 print getTitleFieldOfList('', 0);
577 print '</tr>';
578 
579 print '<tr class="oddeven">';
580 // From warehouse
581 print '<td>';
582 print img_picto($langs->trans("WarehouseSource"), 'stock', 'class="paddingright"').$formproduct->selectWarehouses($id_sw, 'id_sw', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, array(), 'minwidth200imp maxwidth200');
583 print '</td>';
584 // To warehouse
585 print '<td>';
586 print img_picto($langs->trans("WarehouseTarget"), 'stock', 'class="paddingright"').$formproduct->selectWarehouses($id_tw, 'id_tw', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, array(), 'minwidth200imp maxwidth200');
587 print '</td>';
588 // Product
589 print '<td>';
590 $filtertype = 0;
591 if (!empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
592  $filtertype = '';
593 }
594 if ($conf->global->PRODUIT_LIMIT_SIZE <= 0) {
595  $limit = '';
596 } else {
597  $limit = $conf->global->PRODUIT_LIMIT_SIZE;
598 }
599 
600 print img_picto($langs->trans("Product"), 'product', 'class="paddingright"');
601 print $form->select_produits($id_product, 'productid', $filtertype, $limit, 0, -1, 2, '', 1, array(), 0, '1', 0, 'minwidth200imp maxwidth300', 1, '', null, 1);
602 print '</td>';
603 // Batch number
604 if (isModEnabled('productbatch')) {
605  print '<td>';
606  print img_picto($langs->trans("LotSerial"), 'lot', 'class="paddingright"');
607  print '<input type="text" name="batch" class="flat maxwidth50" value="'.$batch.'">';
608  print '</td>';
609 }
610 // Qty
611 print '<td class="center"><input type="text" class="flat maxwidth50" name="qty" value="'.$qty.'"></td>';
612 // Button to add line
613 print '<td class="right"><input type="submit" class="button" name="addline" value="'.dol_escape_htmltag($titletoadd).'"></td>';
614 
615 print '</tr>';
616 
617 foreach ($listofdata as $key => $val) {
618  $productstatic->fetch($val['id_product']);
619  $warehousestatics->fetch($val['id_sw']);
620  $warehousestatict->fetch($val['id_tw']);
621 
622  if ($productstatic->id <= 0) {
623  $error++;
624  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("Product")), null, 'errors');
625  }
626  if ($warehousestatics->id <= 0) {
627  $error++;
628  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("WarehouseSource")), null, 'errors');
629  }
630  if ($warehousestatics->id <= 0) {
631  $error++;
632  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("WarehouseTarget")), null, 'errors');
633  }
634 
635  if (!$error) {
636  print '<tr class="oddeven">';
637  print '<td>';
638  print $warehousestatics->getNomUrl(1);
639  print '</td>';
640  print '<td>';
641  print $warehousestatict->getNomUrl(1);
642  print '</td>';
643  print '<td>';
644  print $productstatic->getNomUrl(1).' - '.$productstatic->label;
645  print '</td>';
646  if (isModEnabled('productbatch')) {
647  print '<td>';
648  print $val['batch'];
649  print '</td>';
650  }
651  print '<td class="center">'.$val['qty'].'</td>';
652  print '<td class="right"><a href="'.$_SERVER["PHP_SELF"].'?action=delline&token='.newToken().'&idline='.$val['id'].'">'.img_delete($langs->trans("Remove")).'</a></td>';
653  print '</tr>';
654  }
655 }
656 
657 print '</table>';
658 print '</div>';
659 
660 print '</form>';
661 
662 print '<br>';
663 
664 // Form to validate all movements
665 if (count($listofdata)) {
666  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire2" class="formconsumeproduce">';
667  print '<input type="hidden" name="token" value="'.newToken().'">';
668  print '<input type="hidden" name="action" value="createmovements">';
669 
670  // Button to record mass movement
671  $codemove = (GETPOSTISSET("codemove") ? GETPOST("codemove", 'alpha') : dol_print_date(dol_now(), '%Y%m%d%H%M%S'));
672  $labelmovement = GETPOST("label") ? GETPOST('label') : $langs->trans("StockTransfer").' '.dol_print_date($now, '%Y-%m-%d %H:%M');
673 
674  print '<div class="center">';
675  print '<span class="fieldrequired">'.$langs->trans("InventoryCode").':</span> ';
676  print '<input type="text" name="codemove" class="maxwidth300" value="'.dol_escape_htmltag($codemove).'"> &nbsp; ';
677  print '<span class="clearbothonsmartphone"></span>';
678  print $langs->trans("MovementLabel").': ';
679  print '<input type="text" name="label" class="minwidth300" value="'.dol_escape_htmltag($labelmovement).'"><br>';
680  print '<br>';
681 
682  print '<div class="center"><input type="submit" class="button" name="valid" value="'.dol_escape_htmltag($buttonrecord).'"></div>';
683 
684  print '<br>';
685  print '</div>';
686 
687  print '</form>';
688 }
689 
690 if ($action == 'delete') {
691  print $form->formconfirm($_SERVER["PHP_SELF"].'?urlfile='.urlencode(GETPOST('urlfile')).'&step=3'.$param, $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile'), 'confirm_deletefile', '', 0, 1);
692 }
693 
694 // End of page
695 llxFooter();
696 $db->close();
697 
705 function startsWith($haystack, $needle)
706 {
707  $length = strlen($needle);
708  return substr($haystack, 0, $length) === $needle;
709 }
710 
718 function fetchref($static_object, $tmp_ref)
719 {
720  if (startsWith($tmp_ref, 'ref:')) {
721  $tmp_ref = str_replace('ref:', '', $tmp_ref);
722  }
723  $static_object->fetch('', $tmp_ref);
724  return $static_object->id;
725 }
restrictedArea
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.
Definition: security.lib.php:234
llxFooter
llxFooter()
Empty footer.
Definition: wrapper.php:73
getTitleFieldOfList
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
Definition: functions.lib.php:5049
load_fiche_titre
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
Definition: functions.lib.php:5204
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
ImportCsv
Class to import CSV files.
Definition: import_csv.modules.php:34
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:142
$help_url
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
startsWith
startsWith($haystack, $needle)
Verify if $haystack startswith $needle.
Definition: massstockmove.php:705
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:3880
dol_delete_file
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1231
getMaxFileSizeArray
getMaxFileSizeArray()
Return the max allowed for file upload.
Definition: security.lib.php:993
img_delete
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
Definition: functions.lib.php:4429
dol_move_uploaded_file
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Make control on an uploaded file from an GUI page and move it to final destination.
Definition: files.lib.php:1092
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
info_admin
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
Definition: functions.lib.php:4800
FormProduct
Class with static methods for building HTML components related to products Only components common to ...
Definition: html.formproduct.class.php:30
newToken
newToken()
Return the value of token currently saved into session with name 'newtoken'.
Definition: functions.lib.php:10878
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:105
GETPOSTISSET
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
Definition: functions.lib.php:386
fetchref
fetchref($static_object, $tmp_ref)
Fetch object with ref.
Definition: massstockmove.php:718
Product
Class to manage products or services.
Definition: product.class.php:46
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:52
Entrepot
Class to manage warehouses.
Definition: entrepot.class.php:35
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
Definition: functions.lib.php:8137
dol_mkdir
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Definition: functions.lib.php:6603
llxHeader
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