Files
IHK-Projekt/03_Realisierung/Code Snippets/HostBooking/InterfaceWcsWms/MessageImplementation/TransportOrderHandler.cs

219 lines
8.2 KiB
C#

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<ITransportOrder>
{
private readonly IDestinationService _destinationService;
private readonly ITransportOrderService _transportOrderService;
private ITransportOrder _transportOrder;
private readonly LeFactory _leFactory = LeFactory.GetInstance();
private readonly List<string> _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);
}
/// <summary>
/// A Handling Unit that rests at a workplace is set to "On conveyer" when it receives a transport order
/// </summary>
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");
}
}
}
}
}