using System; using System.Collections.Generic; using System.IO; using System.Linq; using AutoMapper.Configuration.Conventions; using Gebhardt.Shared; using Gebhardt.StoreWare.Wcs.Common.Application.TransportHandling.Interfaces; using Gebhardt.StoreWare.Wcs.Common.DbAccess; using Gebhardt.StoreWare.Wcs.Common.DbAccess.Factories; using Gebhardt.StoreWare.Wcs.Common.DbAccess.Model; using Gebhardt.StoreWare.Wcs.Common.DbAccess.Model.Enums; using Gebhardt.StoreWare.Wcs.Common.DbAccess.Queries; using Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.Interfaces; using Gebhardt.StoreWare.WcsWms.InterfaceWcsWms.Interfaces; using Microsoft.EntityFrameworkCore; using static Gebhardt.StoreWare.Wcs.Common.ConstantsCommon; namespace Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.MessageImplementation { public class TransportOrderHandler : IHandleRecord { private readonly IDestinationService _destinationService; private readonly ITransportOrderService _transportOrderService; private ITransportOrder _transportOrder; private readonly LeFactory _leFactory = LeFactory.GetInstance(); private readonly List _allStorageAndEmptyLeBufferDestinations; public TransportOrderHandler(IDestinationService destinationService, ITransportOrderService transportOrderService) { _destinationService = destinationService; _transportOrderService = transportOrderService; _allStorageAndEmptyLeBufferDestinations = _destinationService.Where(d => d.IsStorage || d.IsStorageArea || d.BuffersEmptyLe).Select(d => d.Name).ToList(); } public bool Handle(ITransportOrder message) { _transportOrder = message; using WcsDbContext db = new(); string leNo = _transportOrder.LeNo; Le le = db.Le.ByLeNo(leNo); if (le == null) { Log.Write(LogLevel.Info, $"HU {leNo} is unknown. Create HU..."); LeTypeName type = LeType.GetLeTypeFromLeNo(leNo); le = db.Add(_leFactory.RegularLe(leNo, type, preferredStorageArea: message.StorageArea)).Entity; db.SaveChanges(); } CheckTransportOrder(); IDestinationProperties destinationProperties = _destinationService.Get(_transportOrder.Destination); if (destinationProperties == null) { throw new TransportDestinationInvalidException($"Unknown destination in {message}"); } if (destinationProperties.IsStorage && !destinationProperties.IsSequencer && le.IsInStorage()) { throw new LeAlreadyInStorageException($"{le} is in storage."); } CheckLeIsReachable(le); //CheckActiveOrdersForLe(); if (_transportOrder.MovementType == TransportOrderType.Storage.ToString()) { le.SetStatus(LeStatus.Created); } else { SetTransportStatus(le); } SetAbcArea(le); // Le is in the old system, but no movement file has been created for it. bool leNeedsMomFile = le.IsHuInOldSystem == true && le.L8OrderCreated == null; CreateTransportOrder(leNeedsMomFile); db.SaveChanges(); return true; } private void CheckTransportOrder() { if (_transportOrder.LeNo == null) { throw new LeNoMissingException("The HU number is is missing."); } if (_destinationService.Get(_transportOrder.Destination) == null) { throw new TransportDestinationInvalidException($"Destination {_transportOrder.Destination} is unknown. Order is confirmed negatively."); } if (string.IsNullOrEmpty(_transportOrder.MovementType)) { throw new FromWmsException($"Field {nameof(_transportOrder.MovementType)} is not set or not known."); } // TODO: Solche Prüfungen sollten in einem Plausiblitätsmodul für LE-Nummern erfolgen, damit sie leicht kundenspezifisch angepasst werden können if (_transportOrder.LeNo.Length < ConstantsLE.LengthBarcodeWithType) { throw new LeNoTooShortException($"HU number '{_transportOrder.LeNo}' is too short. Should be {ConstantsLE.LengthBarcodeWithType} digits"); } if (_transportOrder.LeNo.Length > ConstantsLE.LengthBarcodeWithType) { throw new LeNoTooLongException($"HU number '{_transportOrder.LeNo}' is too long. Should be {ConstantsLE.LengthBarcodeWithType} digits"); } } private void SetAbcArea(Le le) { //le.AbcArea = _transportOrder.AbcArea; } private void CreateTransportOrder(bool oldSystemBoxRequiringMomFile = false) { using WcsDbContext db = new(); string source = _transportOrder.Source; OrderTypeWms? typeWmsForOrderHost; if (!Enum.TryParse(_transportOrder.MovementType, true, out OrderTypeWms typeWms)) { Log.Write(LogLevel.Error, $"could not parse '{_transportOrder.MovementType}'"); typeWmsForOrderHost = null; } else { typeWmsForOrderHost = typeWms; } OrdersHost ordersHost = OrdersHostFactory.GetInstance().InitialForLe(_transportOrder.LeNo, TransportOrderType.TransportHost, source == TestToolConstants.TestToolSource ? Common.Constants.MfcAllDestinations.AKL01 : source, _transportOrder.Destination, idOrderWms: _transportOrder.IdOrderWms, idOrderWmsHead: _transportOrder.IdOrderWmsHead, idOrderWmsPos: _transportOrder.IdOrderWmsPos, typeWms: typeWmsForOrderHost); IDestinationProperties destination = _destinationService.Get(_transportOrder.Destination); if (destination != null && destination.IsAfterSequencer) { ordersHost.Destination = destination.ConnectedSequencer; ordersHost.HostDestination = _transportOrder.Destination; } // TODO 15585 ordersHost.SequenceWms = _transportOrder.Sequence; ordersHost.IsDirectPicking = _transportOrder.IsDirectPicking; ordersHost.PriorityDate = _transportOrder.Priority; db.Add(ordersHost); if (source == TestToolConstants.TestToolSource) { ordersHost.Priority = TestToolConstants.TestToolPriority; } if (oldSystemBoxRequiringMomFile) { try { CreateMomFile(ordersHost.LeNo); ordersHost.Le.L8OrderCreated = DateTime.Now; Log.Write(LogLevel.Info, $"Mom file created and saved for HU {ordersHost.LeNo}."); } catch (Exception e) { Log.Write(LogLevel.Error, $"Error creating mom file for HU {ordersHost.LeNo}, Exception: {e}"); } } db.SaveChanges(); } private void CreateMomFile(string huNumber) { // Hardcoded since very temporary string filePath = $@"\\10.101.71.32\\InterfaceFiles\\ProdGB\\OrdersGB\\{huNumber}_{DateTime.Now:yyyyMMddHHmmss00}.mom"; File.WriteAllText(filePath, huNumber); } /// /// A Handling Unit that rests at a workplace is set to "On conveyer" when it receives a transport order /// private void SetTransportStatus(Le le) { if (le.Status != LeStatus.InStorage) { le.SetStatus(LeStatus.OnConveyor, le.LastWhere); } } private void CheckLeIsReachable(Le le) { if (le.IsInStorage()) { bool? storageDeviceHasCriticalFault = new WcsDbContext().AisleForLe.GetAisle(le.AisleName, le.StorageArea)?.StorageDevices.Any(s => s.HasCriticalFault); if (storageDeviceHasCriticalFault == null) { Log.Write(LogLevel.Error, $"Unknown aisle {le.AisleName} LE: {le.LeNo}."); } else if (storageDeviceHasCriticalFault.Value) { // This throw causes, that the TransportOrder in FromWms will be frozen in status 'Failed'. // Maybe the order gets then forgotten. Log.Write(LogLevel.Error, $"Order for Le {le.LeNo} will be delayed: {le.AisleName} has a critical fault."); } } } private void CheckActiveOrdersForLe() { //is the an order to a storage location or EMB? if (_allStorageAndEmptyLeBufferDestinations.Contains(_transportOrder.Destination)) { using WcsDbContext db = new(); OrdersHost ordersHost = db.OrdersHost.AsNoTracking(). ByLeNo(_transportOrder.LeNo). Open(). ByDestination(_allStorageAndEmptyLeBufferDestinations).FirstOrDefault(); if (ordersHost != null) { // Replace all open orders to storage or EMB with the new destination _transportOrderService.CancelOrdersHost(ordersHost.Id, $"OH on the way to storage or EMB was ordered to a commisioning destination. This order is cancelled and replaced by this new host order with IdOrderWms {_transportOrder.IdOrderWms}."); Log.Write(LogLevel.Info, $"HU {ordersHost.LeNo} with destination EMB or storage was ordered to a commisioning destination. The previous OH with IdOrderWms {ordersHost.IdOrderWms} was cancelled"); } } } } }