dolibarr  18.0.6
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 
344  // Loop on each line in CSV file
345  while (($i < $nblinesrecord) && !$error) {
346  $newrecord = $importcsv->import_read_record();
347 
348  $data[$i] = $newrecord;
349  if (count($data[$i]) == 1) {
350  // Only 1 empty line
351  unset($data[$i]);
352  $i++;
353  continue;
354  }
355 
356  $tmp_id_sw = $data[$i][0]['val'];
357  $tmp_id_tw = $data[$i][1]['val'];
358  $tmp_id_product = $data[$i][2]['val'];
359  $tmp_qty = $data[$i][3]['val'];
360  $tmp_batch = $data[$i][4]['val'];
361 
362  $errorforproduct = 0;
363  $isidorref = 'ref';
364  if (!is_numeric($tmp_id_product) && $tmp_id_product != '' && preg_match('/^id:/i', $tmp_id_product)) {
365  $isidorref = 'id';
366  }
367  $tmp_id_product = preg_replace('/^(id|ref):/i', '', $tmp_id_product);
368 
369  if ($isidorref === 'ref') {
370  $tmp_id_product = preg_replace('/^ref:/', '', $tmp_id_product);
371  $result = fetchref($productstatic, $tmp_id_product);
372  if ($result === -2) {
373  $error++;
374  $errorforproduct = 1;
375  $langs->load("errors");
376  setEventMessages($langs->trans("ErrorMultipleRecordFoundFromRef", $tmp_id_product), null, 'errors');
377  } elseif ($result <= 0) {
378  $error++;
379  $errorforproduct = 1;
380  $langs->load("errors");
381  setEventMessages($langs->trans("ErrorRefNotFound", $tmp_id_product), null, 'errors');
382  }
383  $tmp_id_product = $result;
384  }
385  $data[$i][2]['val'] = $tmp_id_product;
386  if (!$errorforproduct && !($tmp_id_product > 0)) {
387  $error++;
388  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
389  }
390 
391  if ($tmp_id_sw !== '') {
392  // For source, we allow empty value
393  $errorforwarehouses = 0;
394  $isidorref = 'ref';
395  if (!is_numeric($tmp_id_sw) && $tmp_id_sw != '' && preg_match('/^id:/i', $tmp_id_sw)) {
396  $isidorref = 'id';
397  }
398  $tmp_id_sw = preg_replace('/^(id|ref):/i', '', $tmp_id_sw);
399  if ($isidorref === 'ref') {
400  $tmp_id_sw = preg_replace('/^ref:/', '', $tmp_id_sw);
401  $result = fetchref($warehousestatics, $tmp_id_sw);
402  if ($result === -2) {
403  $error++;
404  $errorforwarehouses = 1;
405  $langs->load("errors");
406  setEventMessages($langs->trans("ErrorMultipleRecordFoundFromRef", $tmp_id_sw), null, 'errors');
407  } elseif ($result <= 0) {
408  $error++;
409  $errorforwarehouses = 1;
410  $langs->load("errors");
411  setEventMessages($langs->trans("ErrorRefNotFound", $tmp_id_sw), null, 'errors');
412  }
413  $tmp_id_sw = $result;
414  }
415  $data[$i][0]['val'] = $tmp_id_sw;
416  if (!$errorforwarehouses && !($tmp_id_sw > 0)) {
417  $error++;
418  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseSource")), null, 'errors');
419  }
420  }
421 
422  $errorforwarehouset = 0;
423  $isidorref = 'ref';
424  if (!is_numeric($tmp_id_tw) && $tmp_id_tw != '' && preg_match('/^id:/i', $tmp_id_tw)) {
425  $isidorref = 'id';
426  }
427  $tmp_id_tw = preg_replace('/^(id|ref):/i', '', $tmp_id_tw);
428  if ($isidorref === 'ref') {
429  $tmp_id_tw = preg_replace('/^ref:/', '', $tmp_id_tw);
430  $result = fetchref($warehousestatict, $tmp_id_tw);
431  if ($result === -2) {
432  $error++;
433  $errorforwarehouset = 1;
434  $langs->load("errors");
435  setEventMessages($langs->trans("ErrorMultipleRecordFoundFromRef", $tmp_id_tw), null, 'errors');
436  } elseif ($result <= 0) {
437  $error++;
438  $errorforwarehouset = 1;
439  $langs->load("errors");
440  setEventMessages($langs->trans("ErrorRefNotFound", $tmp_id_tw), null, 'errors');
441  }
442  $tmp_id_tw = $result;
443  }
444  $data[$i][1]['val'] = $tmp_id_tw;
445  if (!$errorforwarehouset && !($tmp_id_tw > 0)) {
446  $error++;
447  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseTarget")), null, 'errors');
448  }
449 
450  // If a source is provided and same than target
451  if ($tmp_id_sw > 0 && $tmp_id_tw == $tmp_id_sw) {
452  $error++;
453  $langs->load("errors");
454  setEventMessages($langs->trans("ErrorWarehouseMustDiffers"), null, 'errors');
455  }
456  if (!$tmp_qty) {
457  $error++;
458  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Qty")), null, 'errors');
459  }
460 
461  // Check a batch number is provided if product need it
462  if (!$error) {
463  $producttmp = new Product($db);
464  $producttmp->fetch($tmp_id_product);
465  if ($producttmp->hasbatch()) {
466  if (empty($tmp_batch)) {
467  $error++;
468  $langs->load("errors");
469  setEventMessages($langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData", $producttmp->ref), null, 'errors');
470  }
471  }
472  }
473 
474  $i++;
475  }
476 
477  if (!$error) {
478  foreach ($data as $key => $value) {
479  if (count(array_keys($listofdata)) > 0) {
480  $id = max(array_keys($listofdata)) + 1;
481  } else {
482  $id = 1;
483  }
484  $tmp_id_sw = $data[$key][0]['val'];
485  $tmp_id_tw = $data[$key][1]['val'];
486  $tmp_id_product = $data[$key][2]['val'];
487  $tmp_qty = $data[$key][3]['val'];
488  $tmp_batch = $data[$key][4]['val'];
489  $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);
490  }
491  }
492  }
493  }
494  if ($error) {
495  $listofdata = array();
496  }
497 
498  $_SESSION['massstockmove'] = json_encode($listofdata);
499 }
500 
501 if ($action == 'confirm_deletefile' && $confirm == 'yes') {
502  $langs->load("other");
503 
504  $param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
505  if ($excludefirstline) {
506  $param .= '&excludefirstline='.urlencode($excludefirstline);
507  }
508  if ($endatlinenb) {
509  $param .= '&endatlinenb='.urlencode($endatlinenb);
510  }
511 
512  $file = $conf->stock->dir_temp.'/'.GETPOST('urlfile'); // Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
513  $ret = dol_delete_file($file);
514  if ($ret) {
515  setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
516  } else {
517  setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
518  }
519  Header('Location: '.$_SERVER["PHP_SELF"]);
520  exit;
521 }
522 
523 
524 /*
525  * View
526  */
527 
528 $now = dol_now();
529 $error = 0;
530 
531 $form = new Form($db);
532 $formproduct = new FormProduct($db);
533 $productstatic = new Product($db);
534 $warehousestatics = new Entrepot($db);
535 $warehousestatict = new Entrepot($db);
536 
537 $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks|DE:Modul_Bestände';
538 
539 $title = $langs->trans('MassMovement');
540 
541 llxHeader('', $title, $help_url);
542 
543 print load_fiche_titre($langs->trans("MassStockTransferShort"), '', 'stock');
544 
545 $titletoadd = $langs->trans("Select");
546 $buttonrecord = $langs->trans("RecordMovements");
547 $titletoaddnoent = $langs->transnoentitiesnoconv("Select");
548 $buttonrecordnoent = $langs->transnoentitiesnoconv("RecordMovements");
549 print '<span class="opacitymedium">'.$langs->trans("SelectProductInAndOutWareHouse", $titletoaddnoent, $buttonrecordnoent).'</span>';
550 
551 print '<br>';
552 //print '<br>';
553 
554 // Form to upload a file
555 print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" METHOD="POST">';
556 print '<input type="hidden" name="token" value="'.newToken().'">';
557 print '<input type="hidden" name="action" value="importCSV">';
558 if (!empty($conf->dol_optimize_smallscreen)) {
559  print '<br>';
560 }
561 print '<span class="opacitymedium">';
562 print $langs->trans("or");
563 print ' ';
564 $importcsv = new ImportCsv($db, 'massstocklist');
565 print $form->textwithpicto($langs->trans('SelectAStockMovementFileToImport'), $langs->transnoentitiesnoconv("InfoTemplateImport", $importcsv->separator));
566 print '</span>';
567 
568 $maxfilesizearray = getMaxFileSizeArray();
569 $maxmin = $maxfilesizearray['maxmin'];
570 if ($maxmin > 0) {
571  print '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
572 }
573 print '<input type="file" name="userfile" size="20" maxlength="80"> &nbsp; &nbsp; ';
574 $out = (empty($conf->global->MAIN_UPLOAD_DOC) ? ' disabled' : '');
575 print '<input type="submit" class="button small smallpaddingimp" value="'.$langs->trans("ImportFromCSV").'"'.$out.' name="sendit">';
576 $out = '';
577 if (!empty($conf->global->MAIN_UPLOAD_DOC)) {
578  $max = $conf->global->MAIN_UPLOAD_DOC; // In Kb
579  $maxphp = @ini_get('upload_max_filesize'); // In unknown
580  if (preg_match('/k$/i', $maxphp)) {
581  $maxphp = preg_replace('/k$/i', '', $maxphp);
582  $maxphp = $maxphp * 1;
583  }
584  if (preg_match('/m$/i', $maxphp)) {
585  $maxphp = preg_replace('/m$/i', '', $maxphp);
586  $maxphp = $maxphp * 1024;
587  }
588  if (preg_match('/g$/i', $maxphp)) {
589  $maxphp = preg_replace('/g$/i', '', $maxphp);
590  $maxphp = $maxphp * 1024 * 1024;
591  }
592  if (preg_match('/t$/i', $maxphp)) {
593  $maxphp = preg_replace('/t$/i', '', $maxphp);
594  $maxphp = $maxphp * 1024 * 1024 * 1024;
595  }
596  $maxphp2 = @ini_get('post_max_size'); // In unknown
597  if (preg_match('/k$/i', $maxphp2)) {
598  $maxphp2 = preg_replace('/k$/i', '', $maxphp2);
599  $maxphp2 = $maxphp2 * 1;
600  }
601  if (preg_match('/m$/i', $maxphp2)) {
602  $maxphp2 = preg_replace('/m$/i', '', $maxphp2);
603  $maxphp2 = $maxphp2 * 1024;
604  }
605  if (preg_match('/g$/i', $maxphp2)) {
606  $maxphp2 = preg_replace('/g$/i', '', $maxphp2);
607  $maxphp2 = $maxphp2 * 1024 * 1024;
608  }
609  if (preg_match('/t$/i', $maxphp2)) {
610  $maxphp2 = preg_replace('/t$/i', '', $maxphp2);
611  $maxphp2 = $maxphp2 * 1024 * 1024 * 1024;
612  }
613  // Now $max and $maxphp and $maxphp2 are in Kb
614  $maxmin = $max;
615  $maxphptoshow = $maxphptoshowparam = '';
616  if ($maxphp > 0) {
617  $maxmin = min($max, $maxphp);
618  $maxphptoshow = $maxphp;
619  $maxphptoshowparam = 'upload_max_filesize';
620  }
621  if ($maxphp2 > 0) {
622  $maxmin = min($max, $maxphp2);
623  if ($maxphp2 < $maxphp) {
624  $maxphptoshow = $maxphp2;
625  $maxphptoshowparam = 'post_max_size';
626  }
627  }
628 
629  $langs->load('other');
630  $out .= ' ';
631  $out .= info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow), 1);
632 } else {
633  $out .= ' ('.$langs->trans("UploadDisabled").')';
634 }
635 print $out;
636 
637 print '</form>';
638 
639 print '<br><br>';
640 
641 // Form to add a line
642 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">';
643 print '<input type="hidden" name="token" value="'.newToken().'">';
644 print '<input type="hidden" name="action" value="addline">';
645 
646 
647 print '<div class="div-table-responsive-no-min">';
648 print '<table class="liste centpercent">';
649 
650 $param = '';
651 
652 print '<tr class="liste_titre">';
653 print getTitleFieldOfList($langs->trans('WarehouseSource'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
654 print getTitleFieldOfList($langs->trans('WarehouseTarget'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
655 print getTitleFieldOfList($langs->trans('Product'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
656 if (isModEnabled('productbatch')) {
657  print getTitleFieldOfList($langs->trans('Batch'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'tagtd maxwidthonsmartphone ');
658 }
659 print getTitleFieldOfList($langs->trans('Qty'), 0, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right tagtd maxwidthonsmartphone ');
660 print getTitleFieldOfList('', 0);
661 print '</tr>';
662 
663 print '<tr class="oddeven">';
664 // From warehouse
665 print '<td class="nowraponall">';
666 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');
667 print '</td>';
668 // To warehouse
669 print '<td class="nowraponall">';
670 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');
671 print '</td>';
672 // Product
673 print '<td class="nowraponall">';
674 $filtertype = 0;
675 if (!empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
676  $filtertype = '';
677 }
678 if ($conf->global->PRODUIT_LIMIT_SIZE <= 0) {
679  $limit = '';
680 } else {
681  $limit = $conf->global->PRODUIT_LIMIT_SIZE;
682 }
683 
684 print img_picto($langs->trans("Product"), 'product', 'class="paddingright"');
685 print $form->select_produits($id_product, 'productid', $filtertype, $limit, 0, -1, 2, '', 1, array(), 0, '1', 0, 'minwidth200imp maxwidth300', 1, '', null, 1);
686 print '</td>';
687 // Batch number
688 if (isModEnabled('productbatch')) {
689  print '<td class="nowraponall">';
690  print img_picto($langs->trans("LotSerial"), 'lot', 'class="paddingright"');
691  print '<input type="text" name="batch" class="flat maxwidth75" value="'.dol_escape_htmltag($batch).'">';
692  print '</td>';
693 }
694 // Qty
695 print '<td class="right"><input type="text" class="flat maxwidth50 right" name="qty" value="'.price2num((float) $qty, 'MS').'"></td>';
696 // Button to add line
697 print '<td class="right"><input type="submit" class="button" name="addline" value="'.dol_escape_htmltag($titletoadd).'"></td>';
698 
699 print '</tr>';
700 
701 foreach ($listofdata as $key => $val) {
702  $productstatic->id = 0;
703  $productstatic->fetch($val['id_product']);
704 
705  $warehousestatics->id = 0;
706  if ($val['id_sw'] > 0) {
707  $warehousestatics->fetch($val['id_sw']);
708  }
709  $warehousestatict->id = 0;
710  if ($val['id_tw'] > 0) {
711  $warehousestatict->fetch($val['id_tw']);
712  }
713 
714  if ($productstatic->id <= 0) {
715  $error++;
716  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("Product").' (id='.$val['id_product'].')'), null, 'errors');
717  }
718  if ($warehousestatics->id < 0) { // We accept 0 for source warehouse id
719  $error++;
720  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("WarehouseSource").' (id='.$val['id_sw'].')'), null, 'errors');
721  }
722  if ($warehousestatict->id <= 0) {
723  $error++;
724  setEventMessages($langs->trans("ObjectNotFound", $langs->transnoentitiesnoconv("WarehouseTarget").' (id='.$val['id_tw'].')'), null, 'errors');
725  }
726 
727  if (!$error) {
728  print '<tr class="oddeven">';
729  print '<td>';
730  if ($warehousestatics->id > 0) {
731  print $warehousestatics->getNomUrl(1);
732  } else {
733  print '<span class="opacitymedium">';
734  print $langs->trans("None");
735  print '</span>';
736  }
737  print '</td>';
738  print '<td>';
739  print $warehousestatict->getNomUrl(1);
740  print '</td>';
741  print '<td>';
742  print $productstatic->getNomUrl(1).' - '.dol_escape_htmltag($productstatic->label);
743  print '</td>';
744  if (isModEnabled('productbatch')) {
745  print '<td>';
746  print dol_escape_htmltag($val['batch']);
747  print '</td>';
748  }
749  print '<td class="right">'.price2num((float) $val['qty'], 'MS').'</td>';
750  print '<td class="right"><a href="'.$_SERVER["PHP_SELF"].'?action=delline&token='.newToken().'&idline='.$val['id'].'">'.img_delete($langs->trans("Remove")).'</a></td>';
751  print '</tr>';
752  }
753 }
754 
755 print '</table>';
756 print '</div>';
757 
758 print '</form>';
759 
760 print '<br>';
761 
762 // Form to validate all movements
763 if (count($listofdata)) {
764  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire2" class="formconsumeproduce">';
765  print '<input type="hidden" name="token" value="'.newToken().'">';
766  print '<input type="hidden" name="action" value="createmovements">';
767 
768  // Button to record mass movement
769  $codemove = (GETPOSTISSET("codemove") ? GETPOST("codemove", 'alpha') : dol_print_date(dol_now(), '%Y%m%d%H%M%S'));
770  $labelmovement = GETPOST("label") ? GETPOST('label') : $langs->trans("MassStockTransferShort").' '.dol_print_date($now, '%Y-%m-%d %H:%M');
771 
772  print '<div class="center">';
773  print '<span class="fieldrequired">'.$langs->trans("InventoryCode").':</span> ';
774  print '<input type="text" name="codemove" class="maxwidth300" value="'.dol_escape_htmltag($codemove).'"> &nbsp; ';
775  print '<span class="clearbothonsmartphone"></span>';
776  print $langs->trans("MovementLabel").': ';
777  print '<input type="text" name="label" class="minwidth300" value="'.dol_escape_htmltag($labelmovement).'"><br>';
778  print '<br>';
779 
780  print '<div class="center"><input type="submit" class="button" name="valid" value="'.dol_escape_htmltag($buttonrecord).'"></div>';
781 
782  print '<br>';
783  print '</div>';
784 
785  print '</form>';
786 }
787 
788 if ($action == 'delete') {
789  print $form->formconfirm($_SERVER["PHP_SELF"].'?urlfile='.urlencode(GETPOST('urlfile')).'&step=3'.$param, $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile'), 'confirm_deletefile', '', 0, 1);
790 }
791 
792 // End of page
793 llxFooter();
794 $db->close();
795 
796 
804 function startsWith($haystack, $needle)
805 {
806  $length = strlen($needle);
807  return substr($haystack, 0, $length) === $needle;
808 }
809 
817 function fetchref($static_object, $tmp_ref)
818 {
819  if (startsWith($tmp_ref, 'ref:')) {
820  $tmp_ref = str_replace('ref:', '', $tmp_ref);
821  }
822  $static_object->id = 0;
823  $static_object->fetch('', $tmp_ref);
824  return $static_object->id;
825 }
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:1356
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:1218
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.