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