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