d

d
mail@pastecode.io avatar
unknown
csharp
2 years ago
15 kB
2
Indexable
Never
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Bastian.Exacta.Automation.Core;
using Bastian.Exacta.Automation.Core.Models;
using Bastian.Exacta.Business.Core.Entities;
using Bastian.Exacta.Business.Core.Interfaces;
using Bastian.Exacta.Business.Persistance.QueryExtensions;
using Bastian.Exacta.Core.PlugIn;

namespace Bastian.Exacta.Puma.PackRoutingScanner
{
    [ProcessType("SCANNER_TYPE_1003")]
    public class PumaPackRoutingScanner : BaseScanner
    {
        #region Constants

        private const string VasDestination = "VAS";

        private const string LidderDestination = "LID";

        private const string StraightRecircDestination = "REC";

        #endregion

        #region Instance Methods

        public override bool CheckForAndQueueUpScan(TagInfo[] readTagList, ref List<WriteTag> clearReadTags)
        {
            

            if (readTagList[this.ScannerInfo.OPCTriggerIndex].LongVal != 0 &&
                readTagList[this.ScannerInfo.OPCTriggerIndex + 1].StringVal.Trim() != string.Empty)
            {
                long trackId = readTagList[this.ScannerInfo.OPCTriggerIndex].LongVal;
                string barcode = SanitizeString(readTagList[this.ScannerInfo.OPCTriggerIndex + 1].StringVal.Trim());

                var vasLane = this.ScannerInfo.LaneInfoList.Where(x => x.OpcFullIndex > 0
                                                                && x.Description.ToUpper().Contains(VasDestination))
                                                        .FirstOrDefault();
                if (vasLane != null)
                {
                    var fullVal = readTagList[(int)vasLane.OpcFullIndex].LongVal;
                    var laneStatus = fullVal > 0;

                    
                    Log.Debug($" vas Lane OpcFullIndex tag value [{fullVal}] at {ScannerInfo.ScannerDesc}");
                    
                    vasLane.Full = laneStatus;
                }

                PackageInfo laneAssignInfo = new PackageInfo
                {
                    PkgBarCode = barcode,
                    TrackID = trackId,
                    ScaleData = string.Empty,
                    ScannerID = this.ScannerInfo.ScannerNum,
                    ScannerIndex = this.ScannerInfo.ScannerIndex,
                    ScanDateTime = DateTime.Now
                };

                this.StartProcessingCarton(laneAssignInfo);

                // Tell controls to clear the track id
                clearReadTags = new WriteTagBuilder()
                        .AddTag(this.ScannerInfo.OPCTriggerIndex, 0)
                        .GetTags();

                readTagList[this.ScannerInfo.OPCTriggerIndex].LongVal = 0;

                // Set scan values as last values
                readTagList[this.ScannerInfo.OPCTriggerIndex].LastLongVal = trackId;
                readTagList[this.ScannerInfo.OPCTriggerIndex + 1].LastStringVal = barcode;

                if (IsContainerNoRead(barcode))
                {
                    this.ScannerInfo.NumberOfNoReads++;
                }
                else
                {
                    this.ScannerInfo.NumberOfReads++;
                }
                this.ScannerInfo.CurrentScanValue = barcode;
                this.ScannerInfo.OldScanValue = barcode;
                this.ScannerInfo.TrackingID = (int)trackId;

                return true;
            }

            // Handle manual input for no reads
            if (!string.IsNullOrWhiteSpace(this.ManualScan) &&
                this.ScannerInfo.TrackingID != 0)
            {
                readTagList[this.ScannerInfo.OPCTriggerIndex].LastLongVal = 0;
                readTagList[this.ScannerInfo.OPCTriggerIndex].LongVal = this.ScannerInfo.TrackingID;
                readTagList[this.ScannerInfo.OPCTriggerIndex + 1].StringVal = this.ManualScan;
                this.ManualScan = string.Empty;
                return this.CheckForAndQueueUpScan(readTagList, ref clearReadTags);
            }

            return false;
        }

        protected override bool ProcessCarton(ref IQueueInfo qInfo)
        {
            PackageInfo laneAssignInfo = (PackageInfo)qInfo;

            string containerName = laneAssignInfo.PkgBarCode;
            int trackingId = (int)laneAssignInfo.TrackID;
            ZoneInfo assignedRoute = ScannerInfo.GetBestRoutingDestination(new object[] { DefaultZone });

            if (IsContainerNoRead(containerName))
            {
                PostGeneralSystemMessage($"Detected no read at {ScannerInfo.ScannerDesc.Trim()}.");

                assignedRoute = ScannerInfo.GetBestRoutingDestination(new object[] { NoReadZone });
            }
            else if (IsContainerMultiRead(containerName))
            {
                PostGeneralSystemMessage($"Detected multi read at {ScannerInfo.ScannerDesc.Trim()}.");

                assignedRoute = ScannerInfo.GetBestRoutingDestination(new object[] { NoReadZone });
            }
            else
            {
                PostGeneralSystemMessage($"Ready to Process Package {containerName} Tracking ID {trackingId} at {ScannerInfo.ScannerDesc.Trim()}");
                using (var unitOfWork = this.UnitOfWorkFactory.Create())
                {
                    //Does Container Exist and Have Work
                    var containerWorkModel = GetRemainingWorkForContainer(unitOfWork, containerName);
                    laneAssignInfo.GuidValList.AddRange(containerWorkModel.OrderIds.Select(o => (Guid?)o));

                    if (containerWorkModel?.DoesContainerExist != true)
                    {
                        PostGeneralSystemMessage($"Container does not exist! {containerName} Tracking ID {trackingId} at {ScannerInfo.ScannerDesc.Trim()}");
                        assignedRoute = ScannerInfo.GetBestRoutingDestination(new object[] { NoContainerFoundZone });
                    }
                    else if (containerWorkModel.QcRequired)
                    {
                        PostGeneralSystemMessage($"Container QC Required!! {containerName} Tracking ID {trackingId} at {ScannerInfo.ScannerDesc.Trim()}");
                        assignedRoute = ScannerInfo.GetBestRoutingDestination(new object[] { ExceptionZone });
                    }
                    else if (CheckForRecircMax(unitOfWork, laneAssignInfo))
                    {
                        PostGeneralSystemMessage(msg: $"Carton {laneAssignInfo.PkgBarCode} Has Reached its Recirc Max ({ScannerInfo.RecircMax}) at this scanner ({ScannerInfo.ScannerDesc}) and will be sent to exception.");

                        assignedRoute = ScannerInfo.GetBestRoutingDestination(new object[] { ExceptionZone });
                    }
                    else if (this.ContainerHasOpenOrShortedPicks(unitOfWork, containerWorkModel))
                    {
                        this.PostGeneralSystemMessage($"Container [{containerName}] has open or shorted picks, routing to QC");

                        assignedRoute = this.ScannerInfo.GetBestRoutingDestination(new object[] { ScannerInfo.DefaultZone });
                    }
                    else if(this.ContainerHasMultipleOrdersOrVas(unitOfWork, containerWorkModel))
                    {
                        this.PostGeneralSystemMessage($"Container [{containerName}] has multiple orders or an order that requires VAS.");

                        assignedRoute = this.ScannerInfo.GetBestRoutingDestination(new object[]
                        {
                            VasDestination
                        });

                        var vasLane = this.ScannerInfo.LaneInfoList.FirstOrDefault(x => x.ControlsDestination == assignedRoute.ControlsDestination);

                        if (vasLane.Full)
                        {
                            this.PostGeneralSystemMessage($"VAS lane is full.  Sending Container [{containerName}] to recirc.");
                            assignedRoute = this.ScannerInfo.GetBestRoutingDestination(new object[]
                            {
                                StraightRecircDestination
                            });
                        }
                    }
                    else
                    {
                        var bestRoutingDestination = this.ScannerInfo.GetBestRoutingDestination(new object[]
                                                                                                {
                                                                                                    LidderDestination
                                                                                                });
                        if (bestRoutingDestination != null)
                        {
                            assignedRoute = bestRoutingDestination;

                            LaneInfo divertLane = ScannerInfo.LaneInfoList.FirstOrDefault(x => x.ControlsDestination == assignedRoute.ControlsDestination);
                            if (divertLane == null || divertLane.OpcDivertIndex == 0)
                            {
                                CompleteRoutingInstructionsForDestination(unitOfWork, assignedRoute.ControlsDestination, laneAssignInfo.PkgBarCode);
                            }

                            PostGeneralSystemMessage($"Container Still has Work! {containerName} Tracking ID {trackingId} at {ScannerInfo.ScannerDesc.Trim()}");
                        }
                    }
                }
            }

            laneAssignInfo.DestinationID = assignedRoute.ControlsDestination;
            ScannerInfo.DefaultDestination = laneAssignInfo.DestinationID;
            laneAssignInfo.AssignedLane = assignedRoute.DestinationDescription;
            ScannerInfo.Destination = laneAssignInfo.AssignedLane;

            //Write Destination to PLC
            laneAssignInfo.DestinationTags = new WriteTagBuilder()
                .AddTag(ScannerInfo.OPCDestinationIndex + 1, laneAssignInfo.DestinationID)
                .AddTag(ScannerInfo.OPCDestinationIndex, laneAssignInfo.TrackID)
                .GetTags();

            PostGeneralSystemMessage($"Route Container {containerName} at {ScannerInfo.ScannerDesc.Trim()} to {laneAssignInfo.AssignedLane}");

            if (ScannerInfo.LaneInfoList.Any(l => l.ControlsDestination == laneAssignInfo.DestinationID) || assignedRoute?.InsertPreScan == true && assignedRoute?.WorkArea != null)
            {
                InsertPrescanRecord(TaskQueue, assignedRoute?.WorkArea ?? ScannerInfo.WorkAreaID, laneAssignInfo);
            }

            return true;
        }

        /// <summary>
        /// Determines if a container has multiple orders or lines in VAS
        /// </summary>
        /// <param name="unitOfWork">The unit of work</param>
        /// <param name="containerWorkModel">The container work model</param>
        /// <returns></returns>
        private bool ContainerHasMultipleOrdersOrVas(IUnitOfWork unitOfWork, ContainerWorkModel containerWorkModel)
        {
            this.PostGeneralSystemMessage($"Checking if container has multiple orders or VAS...");

            var container = this.RepositoryFactory.Create<Container>(unitOfWork)
                                .Query()
                                .FirstOrDefault(cntnr => cntnr.Name == containerWorkModel.Name);

            var orderSubLineRepo = this.RepositoryFactory.Create<OrderSubLine>(unitOfWork);

            var containerOrderCount = orderSubLineRepo
                                          .Query()
                                          .Where(osl => osl.TransportContainer.Name == containerWorkModel.Name)
                                          .Select(osl => osl.OrderLine.Order.Id)
                                          .Distinct()
                                          .Count();

            this.PostGeneralSystemMessage($"Container [{containerWorkModel.Name}] has [{containerOrderCount}] order and is container type [{container?.Type.Type}]");

            var containerHasMultipleOrders = containerOrderCount > 1 || container?.Type.Type == (decimal)ContainerCategory.MANUFACTURING_TOTE;

            var orderLinesInContainer = orderSubLineRepo.Query()
                                                        .Where(osl => osl.TransportContainer.Name == containerWorkModel.Name)
                                                        .Select(osl => osl.OrderLine.Id)
                                                        .ToList();

            var ordersInContainer = this.RepositoryFactory.Create<OrderLine>(unitOfWork)
                                        .Query()
                                        .Where(line => orderLinesInContainer.Contains(line.Id))
                                        .Select(line => line.Order.Id)
                                        .Distinct()
                                        .ToList();

            var containerHasVas = this.RepositoryFactory.Create<Vas>(unitOfWork)
                                      .Query()
                                      .Any(vas => ordersInContainer.Contains(vas.Order.Id) || orderLinesInContainer.Contains(vas.OrderLine.Id) || vas.Container.Id == containerWorkModel.Id);

            this.PostGeneralSystemMessage(containerHasVas
                                              ? $"Container [{containerWorkModel.Name}] DOES have VAS"
                                              : $"Container [{containerWorkModel.Name}] DOES NOT have VAS");

            return containerHasMultipleOrders || containerHasVas;
        }

        /// <summary>
        /// Determines if the order has open or shorted picks
        /// </summary>
        /// <param name="unitOfWork">The unit of work</param>
        /// <param name="containerWorkModel">The container work model</param>
        /// <returns></returns>
        private bool ContainerHasOpenOrShortedPicks(IUnitOfWork unitOfWork, ContainerWorkModel containerWorkModel)
        {
            bool openPicks = containerWorkModel.PickOrderIds.Any();

            bool shortedPicks = this.RepositoryFactory.Create<OrderSubLine>(unitOfWork)
                                    .Query()
                                    .Any(subLine => containerWorkModel.OrderIds.Contains(subLine.OrderLine.Order.Id) && subLine.Status == OrderSubLineStatus.NEEDS_REALLOCATION);

            return openPicks || shortedPicks;
        }



        #endregion
    }
}