dolibarr  19.0.0-dev
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>';
484 
485 print '<br>';
486 //print '<br>';
487 
488 // Form to upload a file
489 print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" METHOD="POST">';
490 print '<input type="hidden" name="token" value="'.newToken().'">';
491 print '<input type="hidden" name="action" value="importCSV">';
492 if (!empty($conf->dol_optimize_smallscreen)) {
493  print '<br>';
494 }
495 print '<span class="opacitymedium">';
496 print $langs->trans("or");
497 print ' ';
498 $importcsv = new ImportCsv($db, 'massstocklist');
499 print $form->textwithpicto($langs->trans('SelectAStockMovementFileToImport'), $langs->transnoentitiesnoconv("InfoTemplateImport", $importcsv->separator));
500 print '</span>';
501 
502 $maxfilesizearray = getMaxFileSizeArray();
503 $maxmin = $maxfilesizearray['maxmin'];
504 if ($maxmin > 0) {
505  print '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
506 }
507 print '<input type="file" name="userfile" size="20" maxlength="80"> &nbsp; &nbsp; ';
508 $out = (empty($conf->global->MAIN_UPLOAD_DOC) ? ' disabled' : '');
509 print '<input type="submit" class="button small smallpaddingimp" value="'.$langs->trans("ImportFromCSV").'"'.$out.' name="sendit">';
510 $out = '';
511 if (!empty($conf->global->MAIN_UPLOAD_DOC)) {
512  $max = $conf->global->MAIN_UPLOAD_DOC; // In Kb
513  $maxphp = @ini_get('upload_max_filesize'); // In unknown
514  if (preg_match('/k$/i', $maxphp)) {
515  $maxphp = preg_replace('/k$/i', '', $maxphp);
516  $maxphp = $maxphp * 1;
517  }
518  if (preg_match('/m$/i', $maxphp)) {
519  $maxphp = preg_replace('/m$/i', '', $maxphp);
520  $maxphp = $maxphp * 1024;
521  }
522  if (preg_match('/g$/i', $maxphp)) {
523  $maxphp = preg_replace('/g$/i', '', $maxphp);
524  $maxphp = $maxphp * 1024 * 1024;
525  }
526  if (preg_match('/t$/i', $maxphp)) {
527  $maxphp = preg_replace('/t$/i', '', $maxphp);
528  $maxphp = $maxphp * 1024 * 1024 * 1024;
529  }
530  $maxphp2 = @ini_get('post_max_size'); // In unknown
531  if (preg_match('/k$/i', $maxphp2)) {
532  $maxphp2 = preg_replace('/k$/i', '', $maxphp2);
533  $maxphp2 = $maxphp2 * 1;
534  }
535  if (preg_match('/m$/i', $maxphp2)) {
536  $maxphp2 = preg_replace('/m$/i', '', $maxphp2);
537  $maxphp2 = $maxphp2 * 1024;
538  }
539  if (preg_match('/g$/i', $maxphp2)) {
540  $maxphp2 = preg_replace('/g$/i', '', $maxphp2);
541  $maxphp2 = $maxphp2 * 1024 * 1024;
542  }
543  if (preg_match('/t$/i', $maxphp2)) {
544  $maxphp2 = preg_replace('/t$/i', '', $maxphp2);
545  $maxphp2 = $maxphp2 * 1024 * 1024 * 1024;
546  }
547  // Now $max and $maxphp and $maxphp2 are in Kb
548  $maxmin = $max;
549  $maxphptoshow = $maxphptoshowparam = '';
550  if ($maxphp > 0) {
551  $maxmin = min($max, $maxphp);
552  $maxphptoshow = $maxphp;
553  $maxphptoshowparam = 'upload_max_filesize';
554  }
555  if ($maxphp2 > 0) {
556  $maxmin = min($max, $maxphp2);
557  if ($maxphp2 < $maxphp) {
558  $maxphptoshow = $maxphp2;
559  $maxphptoshowparam = 'post_max_size';
560  }
561  }
562 
563  $langs->load('other');
564  $out .= ' ';
565  $out .= info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow), 1);
566 } else {
567  $out .= ' ('.$langs->trans("UploadDisabled").')';
568 }
569 print $out;
570 
571 print '</form>';
572 
573 print '<br><br>';
574 
575 // Form to add a line
576 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">';
577 print '<input type="hidden" name="token" value="'.newToken().'">';
578 print '<input type="hidden" name="action" value="addline">';
579 
580 
581 print '<div class="div-table-responsive-no-min">';
582 print '<table class="liste centpercent">';
583 
584 $param = '';
585 
586 print '<tr class="liste_titre">';
587 print getTitleFieldOfList($langs->trans('WarehouseSource'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
588 print getTitleFieldOfList($langs->trans('WarehouseTarget'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
589 print getTitleFieldOfList($langs->trans('Product'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
590 if (isModEnabled('productbatch')) {
591  print getTitleFieldOfList($langs->trans('Batch'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
592 }
593 print getTitleFieldOfList($langs->trans('Qty'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right tagtd maxwidthonsmartphone ');
594 print getTitleFieldOfList('', 0);
595 print '</tr>';
596 
597 print '<tr class="oddeven">';
598 // From warehouse
599 print '<td class="nowraponall">';
600 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');
601 print '</td>';
602 // To warehouse
603 print '<td class="nowraponall">';
604 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');
605 print '</td>';
606 // Product
607 print '<td class="nowraponall">';
608 $filtertype = 0;
609 if (!empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
610  $filtertype = '';
611 }
612 if ($conf->global->PRODUIT_LIMIT_SIZE <= 0) {
613  $limit = '';
614 } else {
615  $limit = $conf->global->PRODUIT_LIMIT_SIZE;
616 }
617 
618 print img_picto($langs->trans("Product"), 'product', 'class="paddingright"');
619 print $form->select_produits($id_product, 'productid', $filtertype, $limit, 0, -1, 2, '', 1, array(), 0, '1', 0, 'minwidth200imp maxwidth300', 1, '', null, 1);
620 print '</td>';
621 // Batch number
622 if (isModEnabled('productbatch')) {
623  print '<td class="nowraponall">';
624  print img_picto($langs->trans("LotSerial"), 'lot', 'class="paddingright"');
625  print '<input type="text" name="batch" class="flat maxwidth75" value="'.dol_escape_htmltag($batch).'">';
626  print '</td>';
627 }
628 // Qty
629 print '<td class="right"><input type="text" class="flat maxwidth50 right" name="qty" value="'.price2num((float) $qty, 'MS').'"></td>';
630 // Button to add line
631 print '<td class="right"><input type="submit" class="button" name="addline" value="'.dol_escape_htmltag($titletoadd).'"></td>';
632 
633 print '</tr>';
634 
635 foreach ($listofdata as $key => $val) {
636  $productstatic->fetch($val['id_product']);
637 
638  $warehousestatics->id = 0;
639  $warehousestatict->id = 0;
640  if ($val['id_sw'] > 0) {
641  $warehousestatics->fetch($val['id_sw']);
642  }
643  if ($val['id_tw'] > 0) {
644  $warehousestatict->fetch($val['id_tw']);
645  }
646 
647  if ($productstatic->id <= 0) {
648  $error++;
649  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("Product")), null, 'errors');
650  }
651  if ($warehousestatics->id < 0) { // We accept 0 for source warehouse id
652  $error++;
653  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("WarehouseSource")), null, 'errors');
654  }
655  if ($warehousestatict->id <= 0) {
656  $error++;
657  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("WarehouseTarget")), null, 'errors');
658  }
659 
660  if (!$error) {
661  print '<tr class="oddeven">';
662  print '<td>';
663  if ($warehousestatics->id > 0) {
664  print $warehousestatics->getNomUrl(1);
665  } else {
666  print '<span class="opacitymedium">';
667  print $langs->trans("None");
668  print '</span>';
669  }
670  print '</td>';
671  print '<td>';
672  print $warehousestatict->getNomUrl(1);
673  print '</td>';
674  print '<td>';
675  print $productstatic->getNomUrl(1).' - '.dol_escape_htmltag($productstatic->label);
676  print '</td>';
677  if (isModEnabled('productbatch')) {
678  print '<td>';
679  print dol_escape_htmltag($val['batch']);
680  print '</td>';
681  }
682  print '<td class="right">'.price2num((float) $val['qty'], 'MS').'</td>';
683  print '<td class="right"><a href="'.$_SERVER["PHP_SELF"].'?action=delline&token='.newToken().'&idline='.$val['id'].'">'.img_delete($langs->trans("Remove")).'</a></td>';
684  print '</tr>';
685  }
686 }
687 
688 print '</table>';
689 print '</div>';
690 
691 print '</form>';
692 
693 print '<br>';
694 
695 // Form to validate all movements
696 if (count($listofdata)) {
697  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire2" class="formconsumeproduce">';
698  print '<input type="hidden" name="token" value="'.newToken().'">';
699  print '<input type="hidden" name="action" value="createmovements">';
700 
701  // Button to record mass movement
702  $codemove = (GETPOSTISSET("codemove") ? GETPOST("codemove", 'alpha') : dol_print_date(dol_now(), '%Y%m%d%H%M%S'));
703  $labelmovement = GETPOST("label") ? GETPOST('label') : $langs->trans("MassStockTransferShort").' '.dol_print_date($now, '%Y-%m-%d %H:%M');
704 
705  print '<div class="center">';
706  print '<span class="fieldrequired">'.$langs->trans("InventoryCode").':</span> ';
707  print '<input type="text" name="codemove" class="maxwidth300" value="'.dol_escape_htmltag($codemove).'"> &nbsp; ';
708  print '<span class="clearbothonsmartphone"></span>';
709  print $langs->trans("MovementLabel").': ';
710  print '<input type="text" name="label" class="minwidth300" value="'.dol_escape_htmltag($labelmovement).'"><br>';
711  print '<br>';
712 
713  print '<div class="center"><input type="submit" class="button" name="valid" value="'.dol_escape_htmltag($buttonrecord).'"></div>';
714 
715  print '<br>';
716  print '</div>';
717 
718  print '</form>';
719 }
720 
721 if ($action == 'delete') {
722  print $form->formconfirm($_SERVER["PHP_SELF"].'?urlfile='.urlencode(GETPOST('urlfile')).'&step=3'.$param, $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile'), 'confirm_deletefile', '', 0, 1);
723 }
724 
725 // End of page
726 llxFooter();
727 $db->close();
728 
729 
737 function startsWith($haystack, $needle)
738 {
739  $length = strlen($needle);
740  return substr($haystack, 0, $length) === $needle;
741 }
742 
750 function fetchref($static_object, $tmp_ref)
751 {
752  if (startsWith($tmp_ref, 'ref:')) {
753  $tmp_ref = str_replace('ref:', '', $tmp_ref);
754  }
755  $static_object->fetch('', $tmp_ref);
756  return $static_object->id;
757 }
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:1334
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:1196
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.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
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)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
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.