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