public async Task <ActionResult> CheckStatus()
        {
            // Find terminal no from request.
            var terminalNo = _identityService.FindTerminalNo(HttpContext.User.Identity);

            // Check whether this terminal has a valid conveyor or not.
            //•	Retrieve [f05_strrtrsts] in TM05_CONVEYOR, where [f05_terminalno] = Terminal No. which is retrieved from section “server” in “toshiba.ini” configurable file.
            var conveyor = await _commonDomain.FindConveyorCodeAsync(terminalNo);

            // If retrieval is failed or retrieved status is “Error” (or 9), system shows the message MSG 8, stop the use case.
            if (conveyor == null)
            {
                return(Json(new { Success = false, Message = ProductManagementResources.MSG8 }));
            }

            // •	Retrieve [f14_devicestatus] and [f14_usepermitclass] from TM14_DEVICE, where [f14_devicecode] = Product Device Code under “Device” section of “toshiba.ini” configurable file.
            //If retrieval is failed OR retrieved status is “Error” (or 2) OR “Offline” (or 1) OR retrieved permit is “Prohibited” (or 1), system shows the message MSG 9, stop the use case


            var offlineStatus  = Constants.F14_DeviceStatus.Offline.ToString("D");
            var errorStatus    = Constants.F14_DeviceStatus.Error.ToString("D");
            var usepermitClass = Constants.F14_UsePermitClass.Prohibited.ToString("D");
            var device         = await _commonDomain.FindDeviceAvailabilityAsync(_configurationService.ProductDeviceCode);

            if (device == null)
            {
                return(Json(new { Success = false, Message = ProductManagementResources.MSG9 }));
            }
            if (device.F14_DeviceStatus.Equals(offlineStatus) || device.F14_DeviceStatus.Equals(errorStatus) || device.F14_UsePermitClass.Equals(usepermitClass))
            {
                return(Json(new { Success = false, Message = ProductManagementResources.MSG9 }));
            }
            return(Json(new { Success = true }));
        }
        /// <summary>
        /// Retrieve product details asynchronously.
        /// </summary>
        /// <returns></returns>
        public async Task <ActionResult> RetrieveProductDetails(RetrieveProductDetailViewModel item)
        {
            try
            {
                // Find terminal no from request.
                var terminalNo = _identityService.FindTerminalNo(HttpContext.User.Identity);

                // Check whether this terminal has a valid conveyor or not.
                //•	Retrieve [f05_strrtrsts] in TM05_CONVEYOR, where [f05_terminalno] = Terminal No. which is retrieved from section “server” in “toshiba.ini” configurable file.
                var conveyor = await _commonDomain.FindConveyorCodeAsync(terminalNo);

                // If retrieval is failed or retrieved status is “Error” (or 9), system shows the message MSG 8, stop the use case.
                if (conveyor == null)
                {
                    //throw new Exception("MSG08");
                    //return Json(new
                    //{
                    //    message = "MSG08"
                    //});
                    return(Json(new { Success = false, Message = ProductManagementResources.MSG8 }));
                }

                // •	Retrieve [f14_devicestatus] and [f14_usepermitclass] from TM14_DEVICE, where [f14_devicecode] = Product Device Code under “Device” section of “toshiba.ini” configurable file.
                //If retrieval is failed OR retrieved status is “Error” (or 2) OR “Offline” (or 1) OR retrieved permit is “Prohibited” (or 1), system shows the message MSG 9, stop the use case


                var offlineStatus  = Constants.F14_DeviceStatus.Offline.ToString("D");
                var errorStatus    = Constants.F14_DeviceStatus.Error.ToString("D");
                var usepermitClass = Constants.F14_UsePermitClass.Prohibited.ToString("D");
                var device         = await _commonDomain.FindDeviceAvailabilityAsync(_configurationService.ProductDeviceCode);

                if (device == null)
                {
                    return(Json(new { Success = false, Message = ProductManagementResources.MSG9 }));
                }
                if (device.F14_DeviceStatus.Equals(offlineStatus) || device.F14_DeviceStatus.Equals(errorStatus) || device.F14_UsePermitClass.Equals(usepermitClass))
                {
                    return(Json(new { Success = false, Message = ProductManagementResources.MSG9 }));
                }
                //TODO: Q&A Nov 24 2016

                var result = await _stockTakingOfProductDomain.RetrieveProductDetailsAsync(item.PalletNo, item.Row, item.Bay, item.Level,
                                                                                           terminalNo);

                if (!result.IsSuccess)
                {
                    return(Json(new { Success = false, Message = ProductManagementResources.MSG47 }));
                }
                //return new HttpStatusCodeResult(HttpStatusCode.OK);
                //return Json(new
                //{
                //    //row = item.Row,
                //    //bay = item.Bay,
                //    //level = item.Level
                //    result,
                //    Success = true,
                //    Message = "Shelf No [" + result.Data.Row + result.Data.Bay + result.Data.Level + "] retrieving ..."
                //});
                return(Json(new { Success = true, Message = "Shelf No [" + result.Data.Row + result.Data.Bay + result.Data.Level + "] retrieving ..." },
                            JsonRequestBehavior.AllowGet));
            }
            catch (Exception exception)
            {
                if ("MSG08".Equals(exception.Message))
                {
                    Response.StatusCode = (int)HttpStatusCode.NotFound;
                    return(Json(new
                    {
                        exception.Message
                    }));
                }
                if ("MSG47".Equals(exception.Message))
                {
                    Response.StatusCode = (int)HttpStatusCode.NotFound;
                    return(Json(new
                    {
                        message = "MSG47"
                    }));
                }
                if ("MSG9".Equals(exception.Message))
                {
                    Response.StatusCode = (int)HttpStatusCode.NotFound;
                    return(Json(new
                    {
                        exception.Message
                    }));
                }

                return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError));
            }
        }
        /// <summary>
        /// Retrieve external pre product asynchronously by using specific conditions.
        /// </summary>
        /// <param name="terminalNo"></param>
        /// <param name="commandNo"></param>
        /// <param name="preProductCode"></param>
        /// <param name="prePdtLotNo"></param>
        /// <param name="tableListingLine"></param>
        /// <param name="row"></param>
        /// <param name="bay"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        public async Task RetrievalExternalPreProductAsync(string terminalNo, string commandNo, string preProductCode, string prePdtLotNo, string tableListingLine)
        {
            // o	Retrieve [f05_strrtrsts] in TM05_CONVEYOR, where [f05_terminalno] = Terminal No. which is retrieved from section “server” in “toshiba.ini” configurable file.
            var conveyor = await _commonDomain.FindConveyorCodeAsync(terminalNo);

            // Conveyor count.
            var statusError = Constants.F05_StrRtrSts.Error.ToString("D");

            if (conveyor == null || statusError.Equals(conveyor.F05_StrRtrSts))
            {
                throw new Exception(HttpMessages.InvalidConveyorStatus);
            }

            /*
             * o	Retrieve [f14_devicestatus] and [f14_usepermitclass] from TM14_DEVICE, where [f14_devicecode] = Pre-product Device Code under “Device” section of “toshiba.ini” configurable file.
             * If retrieval is failed OR retrieved status is “Error” (or 2) OR “Offline” (or 1) OR retrieved permit is “Prohibited” (or 1), system shows the message MSG 9, stop the use case.
             */
            var device = await _commonDomain.FindDeviceAvailabilityAsync(_configurationService.ProductDeviceCode);

            // Enum conversion.
            var statusOffline     = Constants.F14_DeviceStatus.Offline.ToString("D");
            var statusDeviceError = Constants.F14_DeviceStatus.Error.ToString("D");
            var statusProhibited  = Constants.F14_UsePermitClass.Prohibited.ToString("D");

            if (device == null || statusOffline.Equals(device.F14_DeviceStatus) ||
                statusDeviceError.Equals(device.F14_DeviceStatus) || device.F14_UsePermitClass.Equals(statusProhibited))
            {
                throw new Exception(HttpMessages.InvalidDeviceAvailability);
            }

            /*
             * 	System will get tablet line from “Line” column of selected row.
             * o	If it is not blank, then continue the use case.
             * o	If it is blank, then update TX41_TBTCMD, in which:
             * •	[f41_kndcmdno] = “Command No” column of selected line,
             * •	[f41_prepdtlotno] = “Pre-product Lot No" column of selected line.
             * Then:
             * •	Set [f41_tabletline] = "TAB0" + [Tabletising Line].
             * If no record is updated after this query, system shows the message MSG 47 and stops the use case.
             */

            var tableListingCommands = _unitOfWork.TabletCommandRepository.GetAll();

            tableListingCommands = tableListingCommands.Where(x => x.F41_KndCmdNo.Trim().Equals(commandNo));
            tableListingCommands = tableListingCommands.Where(x => x.F41_PrePdtLotNo.Trim().Equals(prePdtLotNo));

            var totalTableListingLines = await tableListingCommands.CountAsync();

            if (totalTableListingLines < 1)
            {
                throw new Exception(HttpMessages.RecordIsBeingModified);
            }

            foreach (var tableListingCommand in tableListingCommands)
            {
                if (string.IsNullOrWhiteSpace(tableListingCommand.F41_TabletLine))
                {
                    tableListingCommand.F41_TabletLine = "TAB0" + tableListingLine.Substring(tableListingLine.Length - 2);
                    _unitOfWork.TabletCommandRepository.Update(tableListingCommand);
                }
            }

            /*
             * System starts the Retrieval process by doing as follow:
             * o	Get Command No, Pre-product Code and Pre-product Lot No of selected row.
             * o	System will get pallet no for the pre-product by doing as follow:
             * •	Suppose Pallet No and Updated Date are temporary variables which are retrieved respectively from [f53_palletno] and [f53_updatedate] in TX53_OUTSIDEPREPDTSTK, in which:
             * 	[f53_outsideprepdtcode] = Pre-product Code of selected row,
             * 	AND [f53_outsideprepdtlotno] = Pre-product Lot No of selected row,
             * 	AND [f53_kndcmdno] = Command No of selected row,
             * 	AND [f53_stockflag] = “In Stock” (or 3),
             * 	Ascending order by [f53_palletseqno].
             * If no matched record from the query, system shows the message MSG 30 and stops the use case.
             */
            var outsidePrePdtStks = _unitOfWork.OutSidePrePdtStkRepository.GetAll();

            outsidePrePdtStks = outsidePrePdtStks.Where(x => x.F53_OutSidePrePdtCode.Trim().Equals(preProductCode.Trim()));
            outsidePrePdtStks = outsidePrePdtStks.Where(x => x.F53_OutSidePrePdtLotNo.Trim().Equals(prePdtLotNo.Trim()));
            outsidePrePdtStks = outsidePrePdtStks.Where(x => x.F53_KndCmdNo.Trim().Equals(commandNo.Trim()));
            outsidePrePdtStks =
                outsidePrePdtStks.Where(x => Constants.F53_StokcFlag.TX53_StkFlg_Stk.Equals(x.F53_StockFlag.Trim()));
            outsidePrePdtStks = outsidePrePdtStks.OrderBy(x => x.F53_PalletSeqNo);

            var totalOutsidePrePdtStk = await outsidePrePdtStks.CountAsync();

            if (totalOutsidePrePdtStk < 1)
            {
                throw new Exception(HttpMessages.RecordIsBeingModified);
            }

            foreach (var outsidePrePdtStk in outsidePrePdtStks)
            {
                outsidePrePdtStk.F53_StockFlag = Constants.F53_StokcFlag.TX53_StkFlg_Rtr;
            }

            var outsidepPdtStk = await outsidePrePdtStks.FirstOrDefaultAsync();

            /*
             * o	System will assign shelf by doing as follow:
             * •	Suppose Row, Bay, Level and Updated Date1 are temporary variables which are retrieved respectively from
             * [f51_shelfrow], [f51_shelfbay], [f51_shelflevel] and [f51_updatedate] in TX51_PDTSHFSTS, in which:
             * 	[f51_palletno] = Pallet No above,
             * 	AND [f51_shelfstatus] = “External Pre-Products Stocked” (or 8).
             * If no record found, system shows the message MSG 47 and stops the use case.
             * •	(Reference xxiv) Update TX51_PDTSHFSTS, in which:
             * 	[f51_shelfrow] = Row above,
             * 	AND [f51_shelfbay] = Bay above,
             * 	AND [f51_shelflevel] = Level above,
             * 	AND [f51_shelfstatus] = “External Pre-Products Stocked” (or 8),
             * 	AND [f51_updatedate] = Updated Date 1 above.
             * If no record updated from the query, system shows the message MSG 47 and stops the use case.
             */

            var productShelfStatuses = _unitOfWork.ProductShelfStatusRepository.GetAll();

            productShelfStatuses = productShelfStatuses.Where(x => x.F51_PalletNo.Trim().Equals(outsidepPdtStk.F53_PalletNo.Trim()));
            productShelfStatuses =
                productShelfStatuses.Where(
                    x => Constants.F51_ShelfStatus.TX51_ShfSts_ExtPrePdt.Equals(x.F51_ShelfStatus));

            var totalProductShelfStatuses = await productShelfStatuses.CountAsync();

            if (totalProductShelfStatuses < 1)
            {
                throw new Exception(HttpMessages.RecordIsBeingModified);
            }

            foreach (var productShelfStatuse in productShelfStatuses)
            {
                productShelfStatuse.F51_ShelfStatus = "5";
                _unitOfWork.ProductShelfStatusRepository.Update(productShelfStatuse);

                break;
            }

            TX51_PdtShfSts pdtShfSts = null;

            foreach (var productShelfStatus in productShelfStatuses)
            {
                pdtShfSts = productShelfStatus;
            }

            /*
             * o	System will assign Tablet command by updating TX41_TBTCMD, in which:
             * •	[f41_kndcmdno] = Command No of selected row,
             * •	AND [f41_prepdtlotno] = Pre-product Lot No of selected row,
             * •	AND [f41_status] = “not yet tabletised” (or 3), OR “Retrieval but stopped” (or 5), OR “Retrieval process” (or 4)
             * If no record updated from the query, system shows the message MSG 47 and stops the use case.
             */
            var tbtCmds = _unitOfWork.TabletCommandRepository.GetAll();

            tbtCmds = tbtCmds.Where(x => x.F41_KndCmdNo.Trim().Equals(commandNo.Trim()) &&
                                    x.F41_PrePdtLotNo.Trim().Equals(prePdtLotNo.Trim())
                                    &&
                                    (Constants.F41_Status.NotTablet.Equals(x.F41_Status.Trim()) ||
                                     Constants.F41_Status.RetrievalingStoped.Equals(x.F41_Status.Trim())));

            if (await tbtCmds.CountAsync() < 1)
            {
                throw new Exception(HttpMessages.RecordIsBeingModified);
            }

            var totalNoManageItems = await _commonDomain.InsertIntoNoManageAsync();

            await _unitOfWork.CommitAsync();

            var serialNo = string.Format("0000{0}", totalNoManageItems);

            serialNo = serialNo.Substring(serialNo.Length - 4);

            /*
             * •	Insert data to TX47_PDTWHSCMD:
             * 	[f47_commandno] = “2000” (for Retrieval),
             * 	[f47_cmdseqno] = Serial No above,
             * 	[f47_commandtype] = “0000”,
             * 	[f47_strrtrtype] = “External pre-product” (or 2),
             * 	[f47_status] = “An instruction” (or 0),
             * 	[f47_priority] = 0,
             * 	[f47_palletno] = Pallet No above,
             * 	[f47_from] = Row + Bay + Level above,
             * 	[f47_to] = [f05_conveyorcode] from “tm05_conveyor” table, where [f05_terminalno] = Terminal No. which is retrieved from section “server” in “toshiba.ini” configurable file,
             * 	[f47_commandsenddate] = blank,
             * 	[f47_commandenddate] = blank,
             * 	[f47_terminalno] = Terminal No. which is retrieved from section “server” in “toshiba.ini” configurable file,
             * 	[f47_pictureno] = “TCPR101F”,
             * 	[f47_abnormalcode] = blank,
             * 	[f47_adddate] = current date time,
             * 	[f47_updatedate] = current date time,
             * 	[f47_updatecount] = blank.
             */
            var f47To = GetConveyorCode(terminalNo);
            var productWarehouseCommand = new TX47_PdtWhsCmd();

            productWarehouseCommand.F47_CommandNo   = Constants.F47_CommandNo.Retrieval.ToString("D");
            productWarehouseCommand.F47_CmdSeqNo    = serialNo;
            productWarehouseCommand.F47_CommandType = "0000";
            productWarehouseCommand.F47_StrRtrType  = Constants.F47_StrRtrType.ExternalPreProduct.ToString("D");
            productWarehouseCommand.F47_Status      = Constants.F47_Status.AnInstruction.ToString("D");
            productWarehouseCommand.F47_Priority    = 0;
            productWarehouseCommand.F47_PalletNo    = outsidepPdtStk.F53_PalletNo;
            if (pdtShfSts != null)
            {
                productWarehouseCommand.F47_From = string.Format("{0}{1}{2}", pdtShfSts.F51_ShelfRow, pdtShfSts.F51_ShelfBay, pdtShfSts.F51_ShelfLevel);
            }
            productWarehouseCommand.F47_To           = f47To;
            productWarehouseCommand.F47_TerminalNo   = terminalNo;
            productWarehouseCommand.F47_PictureNo    = Constants.PictureNo.TCPR101F;
            productWarehouseCommand.F47_AddDate      = DateTime.Now;
            productWarehouseCommand.F47_UpdateDate   = DateTime.Now;
            productWarehouseCommand.F47_AbnormalCode = "";

            _unitOfWork.ProductWarehouseCommandRepository.Add(productWarehouseCommand);

            // Save changes into database.
            await _unitOfWork.CommitAsync();

            // Broadcast message to third communication.
            _notificationService.SendMessageToC3("TCPR101F", _notificationService.FormatThirdCommunicationMessageResponse(productWarehouseCommand));
        }
        /// <summary>
        /// Restore product asynchronously
        /// </summary>
        /// <param name="terminalNo"></param>
        /// <param name="palletNo"></param>
        /// <param name="items"></param>
        /// <param name="row"></param>
        /// <param name="bay"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        public async Task RestoreProductsAsync(string terminalNo, string palletNo,
                                               IList <StockTakingOfProductConfirmItem> items,
                                               string row, string bay, string level)
        {
            // Find conveyor from terminal no.
            var conveyor = await _commonDomain.FindConveyorCodeAsync(terminalNo);

            // Convert enum to string.
            var conveyorStatusError = Constants.F05_StrRtrSts.Error.ToString("D");

            //If retrieval is failed or retrieved status is “Error” (or 9), system shows the message MSG 8, stop the use case.
            if (conveyor == null || conveyorStatusError.Equals(conveyor.F05_StrRtrSts.Trim()))
            {
                throw new Exception(HttpMessages.InvalidConveyorStatus);
            }

            /*
             * o	Retrieve [f14_devicestatus] and [f14_usepermitclass] from TM14_DEVICE, where [f14_devicecode] = Product Device Code under “Device” section of “toshiba.ini” configurable file.
             * If retrieval is failed OR retrieved status is “Error” (or 2) OR “Offline” (or 1) OR retrieved permit is “Prohibited” (or 1), system shows the message MSG 9, stop the use case.
             */
            var devices = _unitOfWork.DeviceRepository.GetAll();

            devices = devices.Where(x => x.F14_DeviceCode.Equals(_configurationService.ProductDeviceCode));

            // Status conversion.
            var statusError          = Constants.F14_DeviceStatus.Error.ToString("D");
            var statusOffline        = Constants.F14_DeviceStatus.Offline.ToString("D");
            var permissionProhibited = Constants.F14_UsePermitClass.Prohibited.ToString("D");

            // Find the first device in the query.
            var device = await devices.FirstOrDefaultAsync();

            if (device == null || statusError.Equals(device.F14_DeviceStatus) ||
                statusOffline.Equals(device.F14_DeviceCode) || permissionProhibited.Equals(device.F14_UsePermitClass))
            {
                throw new Exception(HttpMessages.InvalidWarehouseStatus);
            }

            /*
             * 	System will delete all data from TX40_PDTSHFSTK, in which [F40_PalletNo] = [Pallet No] textbox value.
             */
            _unitOfWork.ProductShelfStockRepository.Delete(x => x.F40_PalletNo.Trim().Equals(palletNo));

            foreach (var item in items)
            {
                var pdtShfStk = new TX40_PdtShfStk();
                pdtShfStk.F40_PalletNo          = palletNo;
                pdtShfStk.F40_PrePdtLotNo       = item.F40_PrePdtLotNo;
                pdtShfStk.F40_ProductCode       = item.F40_ProductCode;
                pdtShfStk.F40_ProductLotNo      = item.F40_ProductLotNo;
                pdtShfStk.F40_StockFlag         = Constants.F40_StockFlag.TX40_StkFlg_Str;
                pdtShfStk.F40_PackageAmount     = item.PackQty;
                pdtShfStk.F40_Fraction          = item.Fraction;
                pdtShfStk.F40_Amount            = item.F09_PackingUnit * item.PackQty + item.Fraction;
                pdtShfStk.F40_TabletingEndDate  = item.F40_Tabletingenddate;
                pdtShfStk.F40_ShippedAmount     = 0;
                pdtShfStk.F40_CertificationFlg  = item.F40_CertificationFlg;
                pdtShfStk.F40_CertificationDate = item.F40_Certificationdate;
                pdtShfStk.F40_AddDate           = item.F40_AddDate;
                pdtShfStk.F40_UpdateDate        = DateTime.Now;

                _unitOfWork.ProductShelfStockRepository.Add(pdtShfStk);
            }

            /*
             * 	Update TX51_PDTSHFSTS, in which:
             * o	[f51_shelfrow] = 2 first ## characters of [Location],
             * o	AND [f51_shelfbay] = 2 middle ## characters of [Location],
             * o	AND [f51_shelflevel] = 2 last ## characters of [Location],
             * o	Then:
             * o	Set [f51_shelfstatus] = “Assigned for Storage” (or 4),
             * o	Set [f51_terminalno] = Terminal No. which is retrieved from section “server” in “toshiba.ini” configurable file,
             * o	Set [f51_updatedate] = current date time.
             */
            var productShelfStatuses = _unitOfWork.ProductShelfStatusRepository.GetAll();

            productShelfStatuses = productShelfStatuses.Where(x => x.F51_ShelfRow.Trim().Equals(row) &&
                                                              x.F51_ShelfBay.Trim().Equals(bay) &&
                                                              x.F51_ShelfLevel.Trim().Equals(level));

            foreach (var productShelfStatus in productShelfStatuses)
            {
                productShelfStatus.F51_ShelfStatus = Constants.F51_ShelfStatus.TX51_ShfSts_RsvStr;
                productShelfStatus.F51_TerminalNo  = terminalNo;
                productShelfStatus.F51_UpdateDate  = DateTime.Now;
                break;
            }

            //o	Insert data into TX47_PDTWHSCMD:
            var pdtWhsCmd = new TX47_PdtWhsCmd();
            var iSeqNo    = await _commonDomain.InsertIntoNoManageAsync();

            pdtWhsCmd.F47_CmdSeqNo    = iSeqNo.ToString("D4");
            pdtWhsCmd.F47_CommandNo   = Constants.F47_CommandNo.StockTakingIn.ToString("D");
            pdtWhsCmd.F47_CommandType = "0000";
            pdtWhsCmd.F47_StrRtrType  = Constants.F47_StrRtrType.Product.ToString("D");
            pdtWhsCmd.F47_Status      = Constants.F47_Status.AnInstruction.ToString("D");
            pdtWhsCmd.F47_Priority    = 0;
            pdtWhsCmd.F47_PalletNo    = palletNo;
            pdtWhsCmd.F47_From        = conveyor.F05_ConveyorCode;
            pdtWhsCmd.F47_To          = string.Format("{0}{1}{2}", row, bay, level);
            pdtWhsCmd.F47_TerminalNo  = terminalNo;
            pdtWhsCmd.F47_PictureNo   = "TCPR062F";
            pdtWhsCmd.F47_RetryCount  = 0;
            pdtWhsCmd.F47_AddDate     = pdtWhsCmd.F47_UpdateDate = DateTime.Now;
            _unitOfWork.ProductWarehouseCommandRepository.Add(pdtWhsCmd);

            _unitOfWork.Commit();

            _notificationService.SendMessageToC3("TCPR062F", _notificationService.FormatThirdCommunicationMessageResponse(pdtWhsCmd));
        }