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