26 require
'../../main.inc.php';
27 require_once DOL_DOCUMENT_ROOT.
'/product/class/product.class.php';
28 require_once DOL_DOCUMENT_ROOT.
'/product/stock/class/entrepot.class.php';
29 require_once DOL_DOCUMENT_ROOT.
'/core/class/html.form.class.php';
30 require_once DOL_DOCUMENT_ROOT.
'/core/class/html.formother.class.php';
31 require_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.commande.class.php';
32 require_once DOL_DOCUMENT_ROOT.
'/product/class/html.formproduct.class.php';
33 require_once DOL_DOCUMENT_ROOT.
'/core/modules/import/import_csv.modules.php';
34 require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
35 require_once DOL_DOCUMENT_ROOT.
'/core/lib/import.lib.php';
37 $confirm =
GETPOST(
'confirm',
'alpha');
38 $filetoimport =
GETPOST(
'filetoimport');
41 $langs->loadLangs(array(
'products',
'stocks',
'orders',
'productbatch'));
44 $hookmanager->initHooks(array(
'massstockmove'));
48 $socid = $user->socid;
54 $action =
GETPOST(
'action',
'aZ09');
55 $id_product =
GETPOST(
'productid',
'int');
56 $id_sw =
GETPOST(
'id_sw',
'int');
57 $id_tw =
GETPOST(
'id_tw',
'int');
62 $sortfield =
GETPOST(
'sortfield',
'aZ09comma');
63 $sortorder =
GETPOST(
'sortorder',
'aZ09comma');
65 if (empty($page) || $page == -1) {
76 $limit =
GETPOST(
'limit',
'int') ?
GETPOST(
'limit',
'int') : $conf->liste_limit;
77 $offset = $limit * $page;
79 $listofdata = array();
80 if (!empty($_SESSION[
'massstockmove'])) {
81 $listofdata = json_decode($_SESSION[
'massstockmove'],
true);
89 if ($action ==
'addline' && !empty($user->rights->stock->mouvement->creer)) {
90 if (!($id_product > 0)) {
92 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Product")),
null,
'errors');
96 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"WarehouseSource")),
null,
'errors');
100 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"WarehouseTarget")),
null,
'errors');
102 if ($id_sw > 0 && $id_tw == $id_sw) {
104 $langs->load(
"errors");
105 setEventMessages($langs->trans(
"ErrorWarehouseMustDiffers"),
null,
'errors');
109 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Qty")),
null,
'errors');
114 $producttmp =
new Product($db);
115 $producttmp->fetch($id_product);
116 if ($producttmp->hasbatch()) {
119 $langs->load(
"errors");
120 setEventMessages($langs->trans(
"ErrorTryToMakeMoveOnProductRequiringBatchData", $producttmp->ref),
null,
'errors');
129 if ($producttmp->hasbatch()) {
135 if (count(array_keys($listofdata)) > 0) {
136 $id = max(array_keys($listofdata)) + 1;
140 $listofdata[$id] = array(
'id'=>$id,
'id_product'=>$id_product,
'qty'=>$qty,
'id_sw'=>$id_sw,
'id_tw'=>$id_tw,
'batch'=>$batch);
141 $_SESSION[
'massstockmove'] = json_encode($listofdata);
151 if ($action ==
'delline' && $idline !=
'' && !empty($user->rights->stock->mouvement->creer)) {
152 if (!empty($listofdata[$idline])) {
153 unset($listofdata[$idline]);
155 if (count($listofdata) > 0) {
156 $_SESSION[
'massstockmove'] = json_encode($listofdata);
158 unset($_SESSION[
'massstockmove']);
162 if ($action ==
'createmovements' && !empty($user->rights->stock->mouvement->creer)) {
167 setEventMessages($langs->trans(
"ErrorFieldRequired"), $langs->transnoentitiesnoconv(
"MovementLabel"),
null,
'errors');
175 foreach ($listofdata as $key => $val) {
177 $id_product = $val[
'id_product'];
178 $id_sw = $val[
'id_sw'];
179 $id_tw = $val[
'id_tw'];
181 $batch = $val[
'batch'];
185 if (!$error && $id_sw <> $id_tw && is_numeric($qty) && $id_product) {
186 $result = $product->fetch($id_product);
188 $product->load_stock(
'novirtual');
192 if (!empty($product->pmp)) {
193 $pricesrc = $product->pmp;
195 $pricedest = $pricesrc;
199 if (empty($conf->productbatch->enabled) || !$product->hasbatch()) {
201 $result1 = $product->correct_stock(
216 $result2 = $product->correct_stock(
230 $arraybatchinfo = $product->loadBatchInfo($batch);
231 if (count($arraybatchinfo) > 0) {
232 $firstrecord = array_shift($arraybatchinfo);
233 $dlc = $firstrecord[
'eatby'];
234 $dluo = $firstrecord[
'sellby'];
246 $result1 = $product->correct_stock_batch(
264 $result2 = $product->correct_stock_batch(
289 unset($_SESSION[
'massstockmove']);
293 header(
"Location: ".DOL_URL_ROOT.
'/product/stock/index.php');
301 if ($action ==
'importCSV' && !empty($user->rights->stock->mouvement->creer)) {
305 $fullpath = $conf->stock->dir_temp.
"/".$user->id.
'-csvfiletotimport.csv';
307 dol_syslog(
"File ".$fullpath.
" was added for import");
310 $langs->load(
"errors");
315 $importcsv =
new ImportCsv($db,
'massstocklist');
318 $nblinesrecord = $importcsv->import_get_nb_of_lines($fullpath)-1;
319 $importcsv->import_open_file($fullpath);
320 $labelsrecord = $importcsv->import_read_record();
322 if ($nblinesrecord < 1) {
323 setEventMessages($langs->trans(
"BadNumberOfLinesMustHaveAtLeastOneLinePlusTitle"),
null,
'errors');
327 $productstatic =
new Product($db);
328 $warehousestatics =
new Entrepot($db);
329 $warehousestatict =
new Entrepot($db);
330 while (($i < $nblinesrecord) && !$error) {
331 $data[] = $importcsv->import_read_record();
332 if (count($data[$i]) == 1) {
339 $tmp_id_sw = $data[$i][0][
'val'];
340 $tmp_id_tw = $data[$i][1][
'val'];
341 $tmp_id_product = $data[$i][2][
'val'];
342 $tmp_qty = $data[$i][3][
'val'];
343 $tmp_batch = $data[$i][4][
'val'];
345 if (!is_numeric($tmp_id_product)) {
346 $result =
fetchref($productstatic, $tmp_id_product);
347 $tmp_id_product = $result;
348 $data[$i][2][
'val'] = $result;
350 if (!($tmp_id_product > 0)) {
352 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Product")),
null,
'errors');
355 if (!is_numeric($tmp_id_sw)) {
356 $result =
fetchref($warehousestatics, $tmp_id_sw);
357 $tmp_id_sw = $result;
358 $data[$i][0][
'val'] = $result;
360 if (!($tmp_id_sw > 0)) {
362 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"WarehouseSource")),
null,
'errors');
365 if (!is_numeric($tmp_id_tw)) {
366 $result =
fetchref($warehousestatict, $tmp_id_tw);
367 $tmp_id_tw = $result;
368 $data[$i][1][
'val'] = $result;
370 if (!($tmp_id_tw > 0)) {
372 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"WarehouseTarget")),
null,
'errors');
375 if ($tmp_id_sw > 0 && $tmp_id_tw == $tmp_id_sw) {
377 $langs->load(
"errors");
378 setEventMessages($langs->trans(
"ErrorWarehouseMustDiffers"),
null,
'errors');
382 setEventMessages($langs->trans(
"ErrorFieldRequired", $langs->transnoentitiesnoconv(
"Qty")),
null,
'errors');
387 $producttmp =
new Product($db);
388 $producttmp->fetch($tmp_id_product);
389 if ($producttmp->hasbatch()) {
390 if (empty($tmp_batch)) {
392 $langs->load(
"errors");
393 setEventMessages($langs->trans(
"ErrorTryToMakeMoveOnProductRequiringBatchData", $producttmp->ref),
null,
'errors');
402 foreach ($data as $key => $value) {
403 if (count(array_keys($listofdata)) > 0) {
404 $id = max(array_keys($listofdata)) + 1;
408 $tmp_id_sw = $data[$key][0][
'val'];
409 $tmp_id_tw = $data[$key][1][
'val'];
410 $tmp_id_product = $data[$key][2][
'val'];
411 $tmp_qty = $data[$key][3][
'val'];
412 $tmp_batch = $data[$key][4][
'val'];
413 $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);
419 $_SESSION[
'massstockmove'] = json_encode($listofdata);
422 if ($action ==
'confirm_deletefile' && $confirm ==
'yes') {
423 $langs->load(
"other");
425 $param =
'&datatoimport='.urlencode($datatoimport).
'&format='.urlencode($format);
426 if ($excludefirstline) {
427 $param .=
'&excludefirstline='.urlencode($excludefirstline);
430 $param .=
'&endatlinenb='.urlencode($endatlinenb);
433 $file = $conf->stock->dir_temp.
'/'.
GETPOST(
'urlfile');
440 Header(
'Location: '.$_SERVER[
"PHP_SELF"]);
454 $productstatic =
new Product($db);
455 $warehousestatics =
new Entrepot($db);
456 $warehousestatict =
new Entrepot($db);
458 $help_url =
'EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks|DE:Modul_Bestände';
460 $title = $langs->trans(
'MassMovement');
464 print
load_fiche_titre($langs->trans(
"MassStockTransferShort"),
'',
'stock');
466 $titletoadd = $langs->trans(
"Select");
467 $buttonrecord = $langs->trans(
"RecordMovement");
468 $titletoaddnoent = $langs->transnoentitiesnoconv(
"Select");
469 $buttonrecordnoent = $langs->transnoentitiesnoconv(
"RecordMovement");
470 print
'<span class="opacitymedium">'.$langs->trans(
"SelectProductInAndOutWareHouse", $titletoaddnoent, $buttonrecordnoent).
'</span><br>';
475 print
'<form name="userfile" action="'.$_SERVER[
"PHP_SELF"].
'" enctype="multipart/form-data" METHOD="POST">';
476 print
'<input type="hidden" name="token" value="'.newToken().
'">';
477 print
'<input type="hidden" name="action" value="importCSV">';
478 print
'<span class="opacitymedium">';
479 print $langs->trans(
"or").
' ';
480 $importcsv =
new ImportCsv($db,
'massstocklist');
481 print
$form->textwithpicto($langs->trans(
'SelectAStockMovementFileToImport'), $langs->transnoentitiesnoconv(
"InfoTemplateImport", $importcsv->separator));
485 $maxmin = $maxfilesizearray[
'maxmin'];
487 print
'<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).
'">';
489 print
'<input type="file" name="userfile" size="20" maxlength="80"> ';
490 $out = (empty($conf->global->MAIN_UPLOAD_DOC) ?
' disabled' :
'');
491 print
'<input type="submit" class="button small" value="'.$langs->trans(
"ImportFromCSV").
'"'.$out.
' name="sendit">';
493 if (!empty($conf->global->MAIN_UPLOAD_DOC)) {
494 $max = $conf->global->MAIN_UPLOAD_DOC;
495 $maxphp = @ini_get(
'upload_max_filesize');
496 if (preg_match(
'/k$/i', $maxphp)) {
497 $maxphp = preg_replace(
'/k$/i',
'', $maxphp);
498 $maxphp = $maxphp * 1;
500 if (preg_match(
'/m$/i', $maxphp)) {
501 $maxphp = preg_replace(
'/m$/i',
'', $maxphp);
502 $maxphp = $maxphp * 1024;
504 if (preg_match(
'/g$/i', $maxphp)) {
505 $maxphp = preg_replace(
'/g$/i',
'', $maxphp);
506 $maxphp = $maxphp * 1024 * 1024;
508 if (preg_match(
'/t$/i', $maxphp)) {
509 $maxphp = preg_replace(
'/t$/i',
'', $maxphp);
510 $maxphp = $maxphp * 1024 * 1024 * 1024;
512 $maxphp2 = @ini_get(
'post_max_size');
513 if (preg_match(
'/k$/i', $maxphp2)) {
514 $maxphp2 = preg_replace(
'/k$/i',
'', $maxphp2);
515 $maxphp2 = $maxphp2 * 1;
517 if (preg_match(
'/m$/i', $maxphp2)) {
518 $maxphp2 = preg_replace(
'/m$/i',
'', $maxphp2);
519 $maxphp2 = $maxphp2 * 1024;
521 if (preg_match(
'/g$/i', $maxphp2)) {
522 $maxphp2 = preg_replace(
'/g$/i',
'', $maxphp2);
523 $maxphp2 = $maxphp2 * 1024 * 1024;
525 if (preg_match(
'/t$/i', $maxphp2)) {
526 $maxphp2 = preg_replace(
'/t$/i',
'', $maxphp2);
527 $maxphp2 = $maxphp2 * 1024 * 1024 * 1024;
531 $maxphptoshow = $maxphptoshowparam =
'';
533 $maxmin = min($max, $maxphp);
534 $maxphptoshow = $maxphp;
535 $maxphptoshowparam =
'upload_max_filesize';
538 $maxmin = min($max, $maxphp2);
539 if ($maxphp2 < $maxphp) {
540 $maxphptoshow = $maxphp2;
541 $maxphptoshowparam =
'post_max_size';
545 $langs->load(
'other');
547 $out .=
info_admin($langs->trans(
"ThisLimitIsDefinedInSetup", $max, $maxphptoshow), 1);
549 $out .=
' ('.$langs->trans(
"UploadDisabled").
')';
558 print
'<form action="'.$_SERVER[
"PHP_SELF"].
'" method="POST" name="formulaire">';
559 print
'<input type="hidden" name="token" value="'.newToken().
'">';
560 print
'<input type="hidden" name="action" value="addline">';
563 print
'<div class="div-table-responsive-no-min">';
564 print
'<table class="liste centpercent">';
568 print
'<tr class="liste_titre">';
569 print
getTitleFieldOfList($langs->trans(
'WarehouseSource'), 0, $_SERVER[
"PHP_SELF"],
'', $param,
'',
'', $sortfield, $sortorder,
'tagtd maxwidthonsmartphone ');
570 print
getTitleFieldOfList($langs->trans(
'WarehouseTarget'), 0, $_SERVER[
"PHP_SELF"],
'', $param,
'',
'', $sortfield, $sortorder,
'tagtd maxwidthonsmartphone ');
571 print
getTitleFieldOfList($langs->trans(
'ProductRef'), 0, $_SERVER[
"PHP_SELF"],
'', $param,
'',
'', $sortfield, $sortorder,
'tagtd maxwidthonsmartphone ');
573 print
getTitleFieldOfList($langs->trans(
'Batch'), 0, $_SERVER[
"PHP_SELF"],
'', $param,
'',
'', $sortfield, $sortorder,
'tagtd maxwidthonsmartphone ');
575 print
getTitleFieldOfList($langs->trans(
'Qty'), 0, $_SERVER[
"PHP_SELF"],
'', $param,
'',
'', $sortfield, $sortorder,
'center tagtd maxwidthonsmartphone ');
579 print
'<tr class="oddeven">';
582 print
img_picto($langs->trans(
"WarehouseSource"),
'stock',
'class="paddingright"').$formproduct->selectWarehouses($id_sw,
'id_sw',
'warehouseopen,warehouseinternal', 1, 0, 0,
'', 0, 0, array(),
'minwidth200imp maxwidth200');
586 print
img_picto($langs->trans(
"WarehouseTarget"),
'stock',
'class="paddingright"').$formproduct->selectWarehouses($id_tw,
'id_tw',
'warehouseopen,warehouseinternal', 1, 0, 0,
'', 0, 0, array(),
'minwidth200imp maxwidth200');
591 if (!empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
594 if ($conf->global->PRODUIT_LIMIT_SIZE <= 0) {
597 $limit = $conf->global->PRODUIT_LIMIT_SIZE;
600 print
img_picto($langs->trans(
"Product"),
'product',
'class="paddingright"');
601 print
$form->select_produits($id_product,
'productid', $filtertype, $limit, 0, -1, 2,
'', 1, array(), 0,
'1', 0,
'minwidth200imp maxwidth300', 1,
'',
null, 1);
606 print
img_picto($langs->trans(
"LotSerial"),
'lot',
'class="paddingright"');
607 print
'<input type="text" name="batch" class="flat maxwidth50" value="'.$batch.
'">';
611 print
'<td class="center"><input type="text" class="flat maxwidth50" name="qty" value="'.$qty.
'"></td>';
613 print
'<td class="right"><input type="submit" class="button" name="addline" value="'.dol_escape_htmltag($titletoadd).
'"></td>';
617 foreach ($listofdata as $key => $val) {
618 $productstatic->fetch($val[
'id_product']);
619 $warehousestatics->fetch($val[
'id_sw']);
620 $warehousestatict->fetch($val[
'id_tw']);
622 if ($productstatic->id <= 0) {
624 setEventMessages($langs->trans(
"ObjectNotFound", $langs->transnoentitiesnoconv(
"Product")),
null,
'errors');
626 if ($warehousestatics->id <= 0) {
628 setEventMessages($langs->trans(
"ObjectNotFound", $langs->transnoentitiesnoconv(
"WarehouseSource")),
null,
'errors');
630 if ($warehousestatics->id <= 0) {
632 setEventMessages($langs->trans(
"ObjectNotFound", $langs->transnoentitiesnoconv(
"WarehouseTarget")),
null,
'errors');
636 print
'<tr class="oddeven">';
638 print $warehousestatics->getNomUrl(1);
641 print $warehousestatict->getNomUrl(1);
644 print $productstatic->getNomUrl(1).
' - '.$productstatic->label;
651 print
'<td class="center">'.$val[
'qty'].
'</td>';
652 print
'<td class="right"><a href="'.$_SERVER[
"PHP_SELF"].
'?action=delline&token='.
newToken().
'&idline='.$val[
'id'].
'">'.
img_delete($langs->trans(
"Remove")).
'</a></td>';
665 if (count($listofdata)) {
666 print
'<form action="'.$_SERVER[
"PHP_SELF"].
'" method="POST" name="formulaire2" class="formconsumeproduce">';
667 print
'<input type="hidden" name="token" value="'.newToken().
'">';
668 print
'<input type="hidden" name="action" value="createmovements">';
674 print
'<div class="center">';
675 print
'<span class="fieldrequired">'.$langs->trans(
"InventoryCode").
':</span> ';
676 print
'<input type="text" name="codemove" class="maxwidth300" value="'.dol_escape_htmltag($codemove).
'"> ';
677 print
'<span class="clearbothonsmartphone"></span>';
678 print $langs->trans(
"MovementLabel").
': ';
679 print
'<input type="text" name="label" class="minwidth300" value="'.dol_escape_htmltag($labelmovement).
'"><br>';
682 print
'<div class="center"><input type="submit" class="button" name="valid" value="'.dol_escape_htmltag($buttonrecord).
'"></div>';
690 if ($action ==
'delete') {
691 print
$form->formconfirm($_SERVER[
"PHP_SELF"].
'?urlfile='.urlencode(
GETPOST(
'urlfile')).
'&step=3'.$param, $langs->trans(
'DeleteFile'), $langs->trans(
'ConfirmDeleteFile'),
'confirm_deletefile',
'', 0, 1);
707 $length = strlen($needle);
708 return substr($haystack, 0, $length) === $needle;
721 $tmp_ref = str_replace(
'ref:',
'', $tmp_ref);
723 $static_object->fetch(
'', $tmp_ref);
724 return $static_object->id;