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