diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
index f9c76a73019..bb18c960aae 100644
--- a/htdocs/langs/en_US/stocks.lang
+++ b/htdocs/langs/en_US/stocks.lang
@@ -245,6 +245,10 @@ UpdateByScaning=Update by scaning
UpdateByScaningProductBarcode=Update by scan (product barcode)
UpdateByScaningLot=Update by scan (lot|serial barcode)
DisableStockChangeOfSubProduct=Deactivate the stock change for all the subproducts of this Kit during this movement.
+ImportFromCSV=Import CSV list of movement
+ChooseFileToImport=Upload file then click on the %s icon to select file as source import file...
+InfoTemplateImport=Uploaded file needs to have this format (* are mandatory fields) : Product_id* | Source_Warehouse_id* | Target_Warehouse_id* | Quantity* | Batch_id
LabelOfInventoryMovemement=Inventory %s
ReOpen=Reopen
-ConfirmFinish=Confirm closing
\ No newline at end of file
+ConfirmFinish=Confirm closing
+
diff --git a/htdocs/product/stock/massstockmove.php b/htdocs/product/stock/massstockmove.php
index 5a5808b04f3..a89e234acfb 100644
--- a/htdocs/product/stock/massstockmove.php
+++ b/htdocs/product/stock/massstockmove.php
@@ -30,6 +30,12 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/modules/import/import_csv.modules.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/import.lib.php';
+
+$confirm = GETPOST('confirm', 'alpha');
+$filetoimport = GETPOST('filetoimport');
// Load translation files required by the page
$langs->loadLangs(array('products', 'stocks', 'orders', 'productbatch'));
@@ -80,6 +86,20 @@ if (!empty($_SESSION['massstockmove'])) {
* Actions
*/
+
+if (GETPOST('sendit') && !empty($conf->global->MAIN_UPLOAD_DOC)) {
+ dol_mkdir($conf->stock->dir_temp);
+ $nowyearmonth = dol_print_date(dol_now(), '%Y%m%d%H%M%S');
+
+ $fullpath = $conf->stock->dir_temp."/".$nowyearmonth.'-'.$_FILES['userfile']['name'];
+ if (dol_move_uploaded_file($_FILES['userfile']['tmp_name'], $fullpath, 1) > 0) {
+ dol_syslog("File ".$fullpath." was added for import");
+ } else {
+ $langs->load("errors");
+ setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
+ }
+}
+
if ($action == 'addline') {
if (!($id_product > 0)) {
$error++;
@@ -288,8 +308,99 @@ if ($action == 'createmovements') {
}
}
+if ($action == 'importCSV') {
+ $importcsv = new ImportCsv($db, 'massstocklist');
+ $dir = $conf->stock->dir_temp;
+ $fullpath = $dir.'/'.$filetoimport;
+ $nblinesrecord = $importcsv->import_get_nb_of_lines($fullpath)-1;
+ $importcsv->import_open_file($fullpath);
+ $labelsrecord = $importcsv->import_read_record();
+ $i=0;
+ $data = array();
+ while ($i < $nblinesrecord) {
+ $data[] = $importcsv->import_read_record();
+ $id_product = $data[$i][0]['val'];
+ $id_sw = $data[$i][1]['val'];
+ $id_tw = $data[$i][2]['val'];
+ $qty = $data[$i][3]['val'];
+ $batch = $data[$i][4]['val'];
+ if (!($id_product > 0)) {
+ $error++;
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
+ }
+ if (!($id_sw > 0)) {
+ $error++;
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseSource")), null, 'errors');
+ }
+ if (!($id_tw > 0)) {
+ $error++;
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WarehouseTarget")), null, 'errors');
+ }
+ if ($id_sw > 0 && $id_tw == $id_sw) {
+ $error++;
+ $langs->load("errors");
+ setEventMessages($langs->trans("ErrorWarehouseMustDiffers"), null, 'errors');
+ }
+ if (!$qty) {
+ $error++;
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Qty")), null, 'errors');
+ }
+ // Check a batch number is provided if product need it
+ if (!$error) {
+ $producttmp = new Product($db);
+ $producttmp->fetch($id_product);
+ if ($producttmp->hasbatch()) {
+ if (empty($batch)) {
+ $error++;
+ $langs->load("errors");
+ setEventMessages($langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData", $producttmp->ref), null, 'errors');
+ }
+ }
+ }
+
+ $i++;
+ }
+ if (!$error) {
+ foreach ($data as $key => $value) {
+ if (count(array_keys($listofdata)) > 0) {
+ $id = max(array_keys($listofdata)) + 1;
+ } else {
+ $id = 1;
+ }
+ $id_product = $data[$key][0]['val'];
+ $id_sw = $data[$key][1]['val'];
+ $id_tw = $data[$key][2]['val'];
+ $qty = $data[$key][3]['val'];
+ $batch = $data[$key][4]['val'];
+ $listofdata[$key] = array('id'=>$key, 'id_product'=>$id_product, 'qty'=>$qty, 'id_sw'=>$id_sw, 'id_tw'=>$id_tw, 'batch'=>$batch);
+ }
+ }
+ $_SESSION['massstockmove'] = json_encode($listofdata);
+}
+
+if ($action == 'confirm_deletefile' && $confirm == 'yes') {
+ $langs->load("other");
+
+ $param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
+ if ($excludefirstline) {
+ $param .= '&excludefirstline='.urlencode($excludefirstline);
+ }
+ if ($endatlinenb) {
+ $param .= '&endatlinenb='.urlencode($endatlinenb);
+ }
+
+ $file = $conf->stock->dir_temp.'/'.GETPOST('urlfile'); // Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
+ $ret = dol_delete_file($file);
+ if ($ret) {
+ setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
+ }
+ Header('Location: '.$_SERVER["PHP_SELF"]);
+ exit;
+}
/*
* View
*/
@@ -411,6 +522,130 @@ print '';
print '';
+print '
';
+
+print '