public void FileProcess_InvalidFileWithMissingColumns_ShouldReturnInvalidFormat()
        {
            const string fileName = "AtrendProductTemplate_MissingColumns.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", fileName);
            var productUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = fileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = productUploader.FileUpload(input);
            FileProcessResult<ProductInputRow> processResult =
                productUploader.FileProcess(new FileProcessInput(_userContext)
                {
                    FileName = uploadResult.TempFileName,
                    FilePath = uploadResult.TempFilePath
                });
            ValidationError validationError = processResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(true, processResult.ValidationResult.HasViolations, validationError.Message);
            Assert.AreEqual("Invalid file structure. Please use approved template!", validationError.Message);
        }
        /// <summary>
        ///     Ensures the process chain of uploading Product info: file upload,process, validation, mapping, address validation,
        ///     warehouse creation, output file generation
        ///     Updates upload status after each step completes
        /// </summary>
        /// <param name="input"></param>
        public void Upload(FileUploadInput input)
        {
            if (input == null) throw new ArgumentNullException("input");

            var uploadStatus = new UploadStatus(input.UploadTraceToken);
            _logger.Information(string.Format("Upload initiated for file: {0}, by {1}", input.FileName,
                input.UserContext));
            try
            {
                //Initiate upload
                UpdateStatus(uploadStatus, UploadStageEnum.UploadInitiated, "Initiating upload process...");
                //Upload file to temp directory
                UpdateStatus(uploadStatus, UploadStageEnum.FileUploadStart, "File upload to temp directory started...");
                FileUploadResult fileUploadResult = FileUpload(input);
                UpdateStatus(uploadStatus, UploadStageEnum.FileUploadEnd, "File upload to temp directory completed.");
                if (fileUploadResult.ValidationResult.HasViolations)
                {
                    UpdateStatus(uploadStatus, UploadStageEnum.UploadCompleted,
                        "Unable to complete upload process. " +
                        fileUploadResult.ValidationResult.ValidationErrors.First().Message);
                    return;
                }
                // Load File Data into memory
                UpdateStatus(uploadStatus, UploadStageEnum.FileProcessStart, "Load file data into memory started...");
                FileProcessResult<ProductInputRow> fileProcessResult =
                    FileProcess(new FileProcessInput(input.UserContext)
                    {
                        FileName = fileUploadResult.TempFileName,
                        FilePath = fileUploadResult.TempFilePath
                    });
                UpdateStatus(uploadStatus, UploadStageEnum.FileProcessEnd, "Load file data into memory completed.");
                if (fileProcessResult.ValidationResult.HasViolations)
                {
                    UpdateStatus(uploadStatus, UploadStageEnum.UploadCompleted,
                        "Unable to complete upload process. " +
                        fileProcessResult.ValidationResult.ValidationErrors.First().Message);
                    return;
                }
                // Validate data
                UpdateStatus(uploadStatus, UploadStageEnum.FileDataValidateStart, "File  data validation started...");
                FileDataValidateResult<ProductInputRow> fileDataValidateResult =
                    FileDataValidate(new FileDataValidateInput<ProductInputRow>(input.UserContext)
                    {
                        FileData = fileProcessResult.FileData
                    });
                FileDataProcessResult<ProductInputRow> fileDataProcessResult = null;
                if (fileDataValidateResult.ValidationResult.HasViolations)
                {
                    UpdateStatus(uploadStatus, UploadStageEnum.FileDataValidateEnd,
                        "File data validation completed. " +
                        fileDataValidateResult.ValidationResult.ValidationErrors.First().Message);
                }
                else
                {
                    UpdateStatus(uploadStatus, UploadStageEnum.FileDataValidateEnd, "File data validation completed.");
                }
                //process data if ready
                if (fileDataValidateResult.ReadyForUpload)
                {
                    UpdateStatus(uploadStatus, UploadStageEnum.FileDataProcessStart, "File data processing started...");
                    fileDataProcessResult =
                        FileDataProcess(new FileDataProcessInput<ProductInputRow>(input.UserContext)
                        {
                            FileData = fileDataValidateResult.FileData
                        });
                    if (fileDataProcessResult.ValidationResult.HasViolations)
                    {
                        UpdateStatus(uploadStatus, UploadStageEnum.FileDataProcessEnd,
                            "File data processing completed. " +
                            fileDataProcessResult.ValidationResult.ValidationErrors.First().Message);
                    }
                    else
                    {
                        UpdateStatus(uploadStatus, UploadStageEnum.FileDataProcessEnd, "File data processing completed.");
                    }
                }

                UpdateStatus(uploadStatus, UploadStageEnum.OutputFileProcessStart, "Output file generation started...");
                OutputFileProcessResult outputFileProcessResult =
                    OutputFileProcess(new OutputFileProcessInput<ProductInputRow>(input.UserContext)
                    {
                        TempFileName = fileUploadResult.TempFileName,
                        TempFilePath = fileUploadResult.TempFilePath,
                        ProcessedFileData =
                            fileDataProcessResult == null
                                ? fileDataValidateResult.FileData
                                : fileDataProcessResult.FileData,
                        HeadersCount = fileProcessResult.HeadersCount
                    });
                UpdateStatus(uploadStatus, UploadStageEnum.OutputFileProcessEnd, "Output file generation completed.");
                UpdateStatus(uploadStatus, UploadStageEnum.UploadCompleted, "Upload process completed.",
                    outputFileProcessResult.OutputFileInfo);
            }
            catch (Exception e)
            {
                UpdateStatus(uploadStatus, UploadStageEnum.UploadCompleted,
                    "Unable to complete upload process. An unexpected error has occurred.");
                _logger.Fatal("Unable to complete upload process. User context: " + input.UserContext, e);
            }
        }
        /// <summary>
        ///     Upload Excel File to temp directory on the server for further processing
        ///     Validates format and structure of the file. Saves temp file to tem directory.
        /// </summary>
        /// <param name="input">FileUploadInput</param>
        /// <returns>FileUploadResult</returns>
        public FileUploadResult FileUpload(FileUploadInput input)
        {
            if (input == null) throw new ArgumentNullException("input");
            _logger.Information(string.Format("Uploading to temp directory. File name:  {0}", input.FileName));
            using (input.InputStream)
            {
                var result = new FileUploadResult(input.UserContext);

                //validate input format
                ValidationResult formatValidationResult = _validator.FileFormatValidate(input.ContentType);
                if (formatValidationResult.HasViolations)
                {
                    result.ValidationResult.ValidationErrors = formatValidationResult.ValidationErrors;
                    return result;
                }

                var uploadedExcel = new XSSFWorkbook(input.InputStream);

                //validate excel file
                ValidationResult excelFileValidationResult = _validator.ExcelFileValidate(uploadedExcel);
                if (excelFileValidationResult.HasViolations)
                {
                    result.ValidationResult.ValidationErrors = excelFileValidationResult.ValidationErrors;
                    return result;
                }

                string tempFileName = Utility.ToUniqueFileName(input.FileName);
                string tempDirectoryPath = FileShareTempFilesPath;
                string tempFilePath = Utility.GetFilePath(tempDirectoryPath, tempFileName);
                using (var fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
                {
                    uploadedExcel.Write(fs);
                    result.TempFileName = tempFileName;
                    result.TempFilePath = tempFilePath;
                }
                return result;
            }
        }
        public void OutputFileProcess_ValidTempFileProcessInputRecords_GeneratesOutputFile()
        {
            const string FileName = "AtrendProductTemplate_Small.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };

            var dummyProcessedData = new List<ProductInputRow>
            {
                new ProductInputRow
                {
                    RowIndex = 1,
                    UploadedProductId = Guid.NewGuid().ToString(),
                    UploadStatus = "Success",
                    UploadMessage = "Success Message"
                }
            };

            var productUploader = EngineContext.Current.Resolve<IProductUploader>();
            FileUploadResult uploadResult = productUploader.FileUpload(input);

            OutputFileProcessResult outputResult =
                productUploader.OutputFileProcess(new OutputFileProcessInput<ProductInputRow>(_userContext)
                {
                    TempFileName = uploadResult.TempFileName,
                    TempFilePath = uploadResult.TempFilePath,
                    ProcessedFileData = dummyProcessedData
                });

            Assert.AreEqual(false, outputResult.ValidationResult.HasViolations);
            Assert.IsTrue(File.Exists(outputResult.OutputFileInfo.FilePath));
        }
        public void Upload_ValidFileUploadInputFromExcelFile_UploadsProductDataFromTheFileUpdatesStatus()
        {
            const string FileName = "Web Map-Reikken (Autosaved) (1) - Copy.xlsx";
            var traceToken = Guid.NewGuid().ToString();
            var testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var productUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var memoryStream = new MemoryStream();
            stream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            var input = new FileUploadInput(_userContext)
            {
                UploadTraceToken = traceToken,
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = memoryStream
            };
            productUploader.Upload(input);
            var uploadStatus = productUploader.GetUploadStatus(traceToken);
            var uploadHistory = productUploader.GetHistory(5, 0);

            Assert.IsNotNull(uploadStatus);
            Assert.IsNotNull(uploadHistory);
            foreach (var uploadStage in uploadStatus.UploadStageTrace)
            {
                Console.WriteLine("{0} : {1}", uploadStage.Stage, uploadStage.Message);
            }
            foreach (var fileInfo in uploadHistory)
            {
                Console.WriteLine("{0} : {1}", fileInfo.UploadDate, fileInfo.FilePath);
            }
        }
        public void FileUpload_ValidFileUploadInputFromExcelFile_UploadsFileToTempLocation()
        {
            const string fileName = "AtrendProductTemplate.xlsx";
            string tempFileDirectoryPath = Path.Combine(_fileSharePath, "Temp");
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", fileName);
            var fileUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = fileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = fileUploader.FileUpload(input);

            Assert.AreEqual(false, uploadResult.ValidationResult.HasViolations);
            Assert.IsTrue(uploadResult.TempFileName.Contains(fileName));
            Assert.IsTrue(uploadResult.TempFilePath.Contains(tempFileDirectoryPath));
        }
        public void FileUpload_ValidFileUploadInputFromNotExcelFile_ReturnsErrorResultFormatNotSupported()
        {
            var fileUploader = EngineContext.Current.Resolve<IProductUploader>();
            var input = new FileUploadInput(_userContext)
            {
                ContentType = "JPG"
            };
            FileUploadResult uploadResult = fileUploader.FileUpload(input);
            ValidationError validationError = uploadResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(true, uploadResult.ValidationResult.HasViolations);
            Assert.AreEqual("JPG format is not supported!", validationError.Message);
        }
        public void FileProcess_ValidFileUploadInputFromExcelFileWithMoreThen10000Rows_ReturnsViolationsDeletesTempFile()
        {
            const string FileName = "AtrendProductTemplate.xlsx";
            const int MaxProductRowsInFile = 10000; // move to config
            const int ActualProductRowsInFile = 10002; // move to config
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var fileUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = fileUploader.FileUpload(input);
            FileProcessResult<ProductInputRow> processResult =
                fileUploader.FileProcess(new FileProcessInput(_userContext)
                {
                    FileName = uploadResult.TempFileName,
                    FilePath = uploadResult.TempFilePath
                });
            ValidationError validationError = processResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(true, processResult.ValidationResult.HasViolations);
            Assert.AreEqual(
                string.Format(
                    "Batch size has been exceeded. Maximum allowed size is {0} rows, file provided has: {1} rows",
                    MaxProductRowsInFile, ActualProductRowsInFile), validationError.Message);
            Assert.AreEqual(false, File.Exists(uploadResult.TempFilePath), "File must be deleted!");
        }
        public void FileUpload_InValidFileUploadInputExcelWithoutSchema_ReturnsErrorResultInvalidFileFormat()
        {
            const string FileName = "RandomExcelFile.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var fileUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = fileUploader.FileUpload(input);
            ValidationError validationError = uploadResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(true, uploadResult.ValidationResult.HasViolations);
            Assert.AreEqual("Invalid file structure. Please use approved template!", validationError.Message);
        }
        public void FileProcess_ValidFileProcessInputWithValidRecords_UploadsFileToTempLocation()
        {
            const string FileName = "AtrendProductTemplate_Small.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var ProductUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = ProductUploader.FileUpload(input);
            FileProcessResult<ProductInputRow> processResult =
                ProductUploader.FileProcess(new FileProcessInput(_userContext)
                {
                    FileName = uploadResult.TempFileName,
                    FilePath = uploadResult.TempFilePath
                });

            Assert.AreEqual(false, processResult.ValidationResult.HasViolations);
            Assert.IsTrue(processResult.FileData.Any());
        }
        public void FileProcess_ValidFileProcessInputWithSomeColumnsInNumericAndSpecialFormat_ShouldProcessAllAsIfTextFormat()
        {
            const string FileName = "AtrendProductTemplate_Small.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var productUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = productUploader.FileUpload(input);
            FileProcessResult<ProductInputRow> processResult =
                productUploader.FileProcess(new FileProcessInput(_userContext)
                {
                    FileName = uploadResult.TempFileName,
                    FilePath = uploadResult.TempFilePath
                });
            ValidationError validationError = processResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(false, processResult.ValidationResult.HasViolations, validationError.Message);
        }
        public void FileProcess_ValidFileProcessInputWithNoRecords_ReturnsErrorResultFileHasNoRecods()
        {
            const string FileName = "AtrendProductTemplate_Empty.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var ProductUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = ProductUploader.FileUpload(input);
            FileProcessResult<ProductInputRow> processResult =
                ProductUploader.FileProcess(new FileProcessInput(_userContext)
                {
                    FileName = uploadResult.TempFileName,
                    FilePath = uploadResult.TempFilePath
                });
            ValidationError validationError = processResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(true, processResult.ValidationResult.HasViolations);
            Assert.AreEqual("No records provided. At least one Product required to initiate upload!",
                validationError.Message);
        }
        public void FileProcess_ValidFileProcessInputWithFullAndEmptyRows_ShouldProcessFullRowsAndIngnoreEmpty()
        {
            const string FileName = "AtrendProductTemplate_FullAndSomeEmptyRows.xlsx";
            string testfilePath = Path.Combine(_fileSharePath, "Test Files", FileName);
            var ProductUploader = EngineContext.Current.Resolve<IProductUploader>();
            var stream = new FileStream(testfilePath, FileMode.Open, FileAccess.Read);
            var input = new FileUploadInput(_userContext)
            {
                ContentLength = stream.Length,
                ContentType = "vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                FileName = FileName,
                InputStream = stream
            };
            FileUploadResult uploadResult = ProductUploader.FileUpload(input);
            FileProcessResult<ProductInputRow> processResult =
                ProductUploader.FileProcess(new FileProcessInput(_userContext)
                {
                    FileName = uploadResult.TempFileName,
                    FilePath = uploadResult.TempFilePath
                });
            ValidationError validationError = processResult.ValidationResult.ValidationErrors.FirstOrDefault() ??
                                              new ValidationError();

            Assert.AreEqual(false, processResult.ValidationResult.HasViolations, validationError.Message);
            Assert.IsTrue(processResult.FileData.TrueForAll(x => !x.AllStringPropertiesNullOrEmpty()),
                "Should not process empty rows!");
        }
        public ActionResult UploadFile(HttpPostedFileBase inputFile)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))
                return AccessDeniedView();

            //a vendor cannot import products
            if (_workContext.CurrentVendor != null)
                return AccessDeniedView();

            if (inputFile == null) throw new ArgumentNullException("inputFile");
            _logger.Debug("Upload file");
            using (inputFile.InputStream)
            {
                // doing it because IE8 sends in full path instead of name
                var fileName = Path.GetFileName(inputFile.FileName);
                var userContext = _workContext.GetUserContext();
                var uploadTraceToken = Guid.NewGuid().ToString();
                // copy to memory and pass it along
                var memoryStream = new MemoryStream();
                inputFile.InputStream.CopyTo(memoryStream);
                memoryStream.Position = 0;

                var fileUploadInput = new FileUploadInput(userContext)
                    {
                        UploadTraceToken = uploadTraceToken,
                        ContentLength = inputFile.ContentLength,
                        FileName = fileName,
                        InputStream = memoryStream,
                        ContentType = inputFile.ContentType
                    };

                Task.Factory.StartNew(() => EngineContext.Current.Resolve<IProductUploader>().Upload(fileUploadInput));

                return View("~/Plugins/Anko.Plugin.Admin.Uploader/Views/Upload/UploadIframe.cshtml", new UploadFileViewModel { UploadTraceToken = uploadTraceToken });
            }
        }