refactor: migrate project structure by reorganizing realization code snippets into documentation and analysis categories.

This commit is contained in:
2026-05-27 10:48:45 +02:00
parent eb82e4e0b2
commit 24c0593f15
116 changed files with 3309 additions and 236 deletions

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Gebhardt.Shared;
using Gebhardt.StoreWare.Wcs.Common.Application.LeHandling.Interfaces;
using Gebhardt.StoreWare.Wcs.Common.Application.LoopStrategy;
using Gebhardt.StoreWare.Wcs.Common.Application.StorageStrategies.Interfaces;
using Gebhardt.StoreWare.Wcs.Common.Application.TransportHandling.Interfaces;
using Gebhardt.StoreWare.Wcs.Common.DbAccess;
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 static Gebhardt.StoreWare.Wcs.Common.Constants;
namespace Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.MessageImplementation
{
public class AcknowledgeTransportCompletedHandler : IHandleRecord<IAcknowledgeTransportCompleted>
{
private readonly IWcsDbContextFactory _dbContextFactory;
private readonly ITransportOrderService _transportOrderService;
private readonly ILeService _leService;
private readonly IDestinationService _destinationService;
private readonly ILoopSelectionService _loopSelectionService;
public AcknowledgeTransportCompletedHandler(IWcsDbContextFactory dbContextFactory, ITransportOrderService transportOrderService, ILeService leService, IDestinationService destinationService, ILoopSelectionService loopSelectionService)
{
_dbContextFactory = dbContextFactory;
_transportOrderService = transportOrderService;
_destinationService = destinationService;
_leService = leService;
_loopSelectionService = loopSelectionService;
}
public bool Handle(IAcknowledgeTransportCompleted message)
{
using (IWcsDbContext db = _dbContextFactory.GetDbContext())
{
List<int> ordersHostIds = db.OrdersHost.Where(o => o.IdOrderWms == message.IdOrderWms).Select(o => o.Id).ToList();
if (ordersHostIds.Any())
{
if (ordersHostIds.Count() > 1)
{
throw new InvalidOperationException($"Multiple OrdersHost found for same WMS id {message.IdOrderWms}");
}
_transportOrderService.FinishOrdersHost(ordersHostIds.Single(), "AcknowledgeTransportCompleted");
Log.Write(LogLevel.Info, $"{nameof(OrdersHost)} with Id {ordersHostIds.Single()} and WMS id {message.IdOrderWms} finished.");
//Other open OH for HU that must be cancelled?
List<OrdersHost> others = db.OrdersHost
.OpenByLeNo(message.LeNo).Where(oh => oh.Type == TransportOrderType.Transport).ToList();
foreach (var other in others)
{
_transportOrderService.CancelOrdersHost(other.Id, $"New destination {message.Destination}", $"OrderHost {ordersHostIds.Single()} was finished");
}
}
else
{
Log.Write(LogLevel.Error, $"{nameof(AcknowledgeTransportCompletedHandler)}: Cannot find OH for WMS id {message.IdOrderWms}");
}
db.SaveChanges();
}
// New DB Context since OrdersConveyorService changes data that we otherwise wouldn't notice
using (IWcsDbContext db = _dbContextFactory.GetDbContext())
{
// le empty?
Le le = db.Le.ByLeNo(message.LeNo);
// If there is no other order for this le, send it back to the storage
if (!db.OrdersHost.OpenByLeNo(message.LeNo).Any() && le != null)
{
DestinationProperty workStation = db.DestinationProperty.FirstOrDefault(d => d.Name == message.Destination && d.Property == nameof(IDestinationProperties.Level));
var workStationDest = _destinationService.Get(message.Destination);
List<VLoopOverview> availableLoops = _loopSelectionService.GetSuitableStorageLoops(message.LeNo);
// Choose a desired destination based on which is the closest to the workstation
string destination = MfcAllDestinations.StorageLoop2;
if (workStationDest != null)
{
destination = workStationDest.StorageArea == MfcAllDestinations.AKL02 ? MfcAllDestinationsOldSystem.LOOP3 : workStationDest.Level == ConveyorLevel.EtraBox.ToString() ? MfcAllDestinations.StorageLoop1 : MfcAllDestinations.StorageLoop2;
// If only one of the loops is available, choose this, no matter where the LE is located
if (availableLoops.Count == 1)
{
destination = availableLoops.First().PlcName;
}
else
{
// Prefer the destination closest connected to the pick station but select the other if this is full
string fallbackDestination = workStationDest.StorageArea == MfcAllDestinations.AKL02 ? MfcAllDestinationsOldSystem.LOOP3 : workStationDest.Level == ConveyorLevel.EtraBox.ToString() ? MfcAllDestinations.StorageLoop1 : MfcAllDestinations.StorageLoop2;
if (!_loopSelectionService.hasEnoughSpace(destination) && _loopSelectionService.hasEnoughSpace(fallbackDestination))
{
destination = fallbackDestination;
}
}
}
string source = message.Destination == MfcAllDestinationsOldSystem.TOPUP ? MfcAllDestinationsOldSystem.TOPUP : message.Source ?? "?";
int ordersHostId = _leService.CreateTransport(message.LeNo, source, destination);
Log.Write(LogLevel.Info, $"Loop selection in acknowledge transport handler for {le.LeNo}, set to {destination}");
LoopStrategy.ReserveForLoop(le.LeNo, ordersHostId, availableLoops.FirstOrDefault(l => l.PlcName == destination)?.Name);
}
}
return true;
}
}
}

View File

@@ -0,0 +1,147 @@
using System.Linq;
using Gebhardt.Shared;
using Gebhardt.StoreWare.Wcs.Common;
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 Gebhardt.StoreWare.WcsWms.InterfaceWcsWms.Models;
namespace Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.MessageImplementation
{
public class DepartureNotificationHandler : IHandleRecord<IDepartureNotification>
{
private readonly IDestinationService _destinationService;
private readonly ITransportOrderService _transportOrderService;
private readonly IWcsDbContextFactory _wcsDbContextFactory;
public DepartureNotificationHandler(IDestinationService destinationService, ITransportOrderService transportOrderService, IWcsDbContextFactory wcsDbContextFactory)
{
_destinationService = destinationService;
_transportOrderService = transportOrderService;
_wcsDbContextFactory = wcsDbContextFactory;
}
public bool Handle(IDepartureNotification message)
{
using IWcsDbContext db = _wcsDbContextFactory.GetDbContext();
// If we don't have the LE, we need to depart. Otherwise we can't get rid of it.
if (db.Le.ByLeNo(message.LeNo) == null || message.LeNo.StartsWith("B") || message.StorageArea.ToLower() == "dummy")
{
ConveyorTelegrams.SendDepartureEtra(db, message.LeNo, message.Position);
//For EtraBoxes we can Finish the OrdersHost here As there is no feedback anymore for this boxes:
if (message.LeNo.StartsWith("B") && message.Position.Contains("PTL"))
{
//Finish all TransportOrders from this PTL Place as the place is empty now.
var etraBoxOrder = db.OrdersHost.ByStatus(TransportOrderStatus.Transmitted).Where(o => o.Source == message.Position);
if (etraBoxOrder.Any())
{
foreach (var oh in etraBoxOrder)
{
oh.Finish();
if (oh.LeNo == message.LeNo)
{
Log.Write(LogLevel.Info, $"EtraBox {oh.LeNo} is pushed off, finish orders host {oh.Id}.");
}
else
{
oh.Info = $"CleanedUp by Departure for {message.LeNo}";
Log.Write(LogLevel.Info, $"EtraBox {oh.LeNo} orders host {oh.Id} is finished because EtraBox {message.LeNo} was pushed off from the same PTL place.");
}
}
}
}
db.SaveChanges();
return true;
}
var openOH = db.OrdersHost.OpenByLeNo(message.LeNo).ToList();
if (!openOH.Any())
{
//Receive and Replenishment places don't need to create a WCS Transport.
if(message.Position.StartsWith(Constants.MfcAllDestinationsOldSystem.IPT01.Substring(0,3)) || message.Position.StartsWith(Constants.MfcAllDestinations.RCV01.Substring(0, 3)) || message.Position== Constants.MfcAllDestinationsOldSystem.TOPUP)
{
//Ignore and go on
return true;
}
OrdersHost ordersHost = OrdersHostFactory.GetInstance()
.InitialForLe(message.LeNo, TransportOrderType.Transport, message.Position, _destinationService.GetDefaultStorage(message.Position));
db.Add(ordersHost);
// Always depart a box on the error stations to prevent blocks
IDestinationProperties destination = _destinationService.Get(message.Position);
if (destination != null && destination.IsNio)
{
ConveyorTelegrams.SendDepartureEtra(db, message.LeNo, message.Position);
ordersHost.Le.SetStatus(LeStatus.OnConveyor);
}
Log.Write(LogLevel.Info, $"Added OrdersHost for {message.LeNo} from {message.Position} to {ordersHost.Destination}.");
}
else
{
// Is there an order to this place InProgress or InDestinationZone? => Start again by setting this order to pending
var currentOrderToPlace = db.OrdersHost
.ByLeNo(message.LeNo)
.ByDestination(message.Position)
.ByStatus(TransportOrderStatus.InProgress, TransportOrderStatus.InDestinationZone)
.FirstOrDefault();
if (currentOrderToPlace != null)
{
if (currentOrderToPlace.Status == TransportOrderStatus.InDestinationZone)
{
IDestinationProperties destination = _destinationService.Get(currentOrderToPlace.Destination);
if (currentOrderToPlace.HostDestination != null)
{
currentOrderToPlace.Destination = destination.ConnectedSequencer;
}
ConveyorTelegrams.SendDepartureEtra(db, message.LeNo, message.Position);
currentOrderToPlace.UpdateResources(TransportOrderStatus.InProgress, null);
currentOrderToPlace.ForceSetStatusInProgress();
currentOrderToPlace.Le.SetStatus(LeStatus.OnConveyor);
db.SaveChanges();
Log.Write(LogLevel.Info, $"OrdersHost for {message.LeNo} to {message.Position} started again by DepartureNotification.");
}
}
else
{
//Todo: Wouldn't it be better to do this in StartInitialOrders?
var otherPicOrder = db.OrdersHost.ByLeNo(message.LeNo)
.ByStatus(TransportOrderStatus.Initial)
.ApplyWmsOrdering()
.FirstOrDefault();
if (otherPicOrder != null)
{
_transportOrderService.StartNextTransport(otherPicOrder.Id);
}
//Set source to TOPUP in case Departure has been sent from TopUP or IPT stations, to be able to accept the box on scale
if (message.Position == Constants.MfcAllDestinationsOldSystem.TOPUP || message.Position.StartsWith(Constants.MfcAllDestinationsOldSystem.IPT01.Substring(0, 3)))
{
var activeOH = openOH.Where(o=>o.Status == TransportOrderStatus.InProgress).FirstOrDefault();
if (activeOH != null)
{
activeOH.Source = Constants.MfcAllDestinationsOldSystem.TOPUP;
}
}
else
{
_destinationService.SetLeRequestDeparture(message.LeNo, message.Position);
ConveyorTelegrams.SendDepartureEtra(db, message.LeNo, message.Position);
db.Le.FirstOrDefault(l => l.LeNo == message.LeNo)?.SetStatus(LeStatus.OnConveyor);
}
db.SaveChanges();
return true;
}
}
// update destination status!
_destinationService.SetLeRequestDeparture(message.LeNo, message.Position);
db.SaveChanges(true);
return true;
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Linq;
using Gebhardt.Shared;
using Gebhardt.StoreWare.Wcs.Common;
using Gebhardt.StoreWare.Wcs.Common.DbAccess;
using Gebhardt.StoreWare.Wcs.Common.DbAccess.Constants;
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;
namespace Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.MessageImplementation
{
public class HuChangeHandler : IHandleRecord<IHuChange>
{
private readonly IWcsDbContextFactory _dbContextFactory;
private readonly LeFactory _leFactory = LeFactory.GetInstance();
public HuChangeHandler(IWcsDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public bool Handle(IHuChange message)
{
using IWcsDbContext db = _dbContextFactory.GetDbContext();
Le le = db.Le.ByLeNo(message.LeNo);
if (le == null)
{
Log.Write(LogLevel.Info, $"HuChange - HU {message.LeNo} is unknown. Create HU...");
LeTypeName type = LeType.GetLeTypeFromLeNo(message.LeNo);
if (type == null)
{
throw new LeNoWrongFormatException($"HuChange - The prefix of {message.LeNo} is not known.");
}
le = db.Add(_leFactory.RegularLe(message.LeNo, type)).Entity;
db.SaveChanges();
}
UpdateLeTypeIfGiven(message, le, db);
le.IsEmpty = message.IsLeEmpty ?? true;
le.AbcArea = !le.IsEmpty ? SetAbcArea(message, le) : null;
le.Subdivision = message.Subdivision?.ToEnumFromDescription<SubdivisionType>() ?? le.Subdivision;
if (le.IsEmpty)
{
le.Weight = le.LeType.TareWeight; // Since there is no scale in the upper loops
le.ArticleTag = null;
}
else
{
le.ArticleTag = message.ArticleTag;
}
db.SaveChanges();
return true;
}
private static string SetAbcArea(IHuChange message, Le le)
{
if (message.AbcArea == null)
{
return le.AbcArea;
}
if (!Area.IsValid(message.AbcArea) && !Area.IsClassificationForOldStorage(message.AbcArea))
{
return Area.Z;
}
return message.AbcArea;
}
private static void UpdateLeTypeIfGiven(IHuChange message, Le le, IWcsDbContext db)
{
if (message.LeType == null)
{
return;
}
if (!Enum.IsDefined(typeof(LeTypeName), message.LeType))
{
throw new InvalidOperationException($"LeType={message.LeType} does not match an enum. Message: {message}");
}
LeType leType = db.LeType.SingleOrDefault(l => l.Name == (LeTypeName)Enum.Parse(typeof(LeTypeName), message.LeType));
if (leType == null)
{
throw new InvalidOperationException($"LeType={message.LeType} does not match exactly one DB entry -. Message: {message}");
}
le.SetLeType(leType);
}
}
}

View File

@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper.Configuration.Conventions;
using Gebhardt.Shared;
using Gebhardt.Shared.DbAccess;
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.Wcs.InterfaceOldPlc.Services;
using Gebhardt.StoreWare.WcsWms.InterfaceWcsWms.EntityFramework;
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 ShipmentTransportOrderHandler : IHandleRecord<IShipmentTransportOrder>
{
private readonly IDestinationService _destinationService;
private readonly ITransportOrderService _transportOrderService;
private IShipmentTransportOrder _shipmentTransportOrder;
private readonly LeFactory _leFactory = LeFactory.GetInstance();
private readonly List<string> _allStorageDestinations;
public ShipmentTransportOrderHandler(IDestinationService destinationService, ITransportOrderService transportOrderService)
{
_destinationService = destinationService;
_transportOrderService = transportOrderService;
_allStorageDestinations = _destinationService.Where(d => d.IsStorage).Select(d => d.Name).ToList();
}
public bool Handle(IShipmentTransportOrder message)
{
_shipmentTransportOrder = message;
using WcsDbContext db = new();
CheckTransportOrder(db);
string cartonNo = _shipmentTransportOrder.LeNo;
Le le = db.Le.ByLeNo(cartonNo);
if (le == null)
{
Log.Write(LogLevel.Info, $"Carton number {cartonNo} is unknown. Creating a new carton...");
// TODO: Add correct prefixes depending on which type of carton? Now it is set as unknown
LeTypeName type = LeType.GetLeTypeFromLeNo(cartonNo);
le = db.Add(_leFactory.RegularLe(cartonNo, type)).Entity;
db.SaveChanges();
}
le.SetStatus(LeStatus.Created);
CreateTransportOrder();
db.SaveChanges();
return true;
}
private void CheckTransportOrder(IWcsDbContext db)
{
if (_shipmentTransportOrder.LeNo == null)
{
throw new FromWmsException("The carton or EtraBox number is missing.");
}
if(_shipmentTransportOrder.Destination == null)
{
throw new FromWmsException("No destination set.");
}
if (_shipmentTransportOrder.LeNo.StartsWith("B"))
{
List<string> allowedEtraBoxDestinations = new List<string>() {"D01", "D02", "D03", "D04", "D05", "D06", "D07", "D08", "D09", "D99", "M01", "M02", "M03", "M04", "M05", "M06", "M07", "M08", "M09", "M10", "M11", "M12" };
if(_shipmentTransportOrder.Destination.Split('/').ToList().Any(d => !allowedEtraBoxDestinations.Contains(d)))
{
throw new FromWmsException("Not allowed destination for EtraBox.");
}
}
else
{
HostEntities dbHost = new HostEntitiesFactory(HostEntities.DefaultConnectionStringName).Create(); ;
var allowedDestinationsForCartons = dbHost.RouteSetting.Select(r => r.WmsRouteName).Distinct().ToList();
if (!allowedDestinationsForCartons.Contains(_shipmentTransportOrder.Destination))
{
throw new FromWmsException("Not allowed destination for Carton/Paperbag/Pallet.");
}
}
//Check if there is already an open order for the same LE (WMS is sending for each Pick)
var openOrdes = db.OrdersHost.ByLeNo(_shipmentTransportOrder.LeNo).ByStatus(TransportOrderStatus.Pending, TransportOrderStatus.Initial, TransportOrderStatus.Transmitted).Where(o=>o.Source == _shipmentTransportOrder.Source && o.Destination == _shipmentTransportOrder.Destination);
if(openOrdes.Any())
{
throw new FromWmsException("Order is already created.");
}
else
{
//Also check Finished orders from the last 2 Minutes, because WMS sometimes sends Departure before the TransportOrder...
var age = DBDateTime.Now - TimeSpan.FromMinutes(2);
openOrdes = db.OrdersHost.ByLeNo(_shipmentTransportOrder.LeNo).ByStatus(TransportOrderStatus.Finished).Where(o => o.Source == _shipmentTransportOrder.Source && o.Destination == _shipmentTransportOrder.Destination && o.Timestamp > age);
if (openOrdes.Any())
{
throw new FromWmsException("Order is already created.");
}
}
}
private void CreateTransportOrder()
{
using WcsDbContext db = new();
string source = _shipmentTransportOrder.Source;
OrdersHost ordersHost = OrdersHostFactory.GetInstance().InitialForLe(_shipmentTransportOrder.LeNo, TransportOrderType.TransportHost, source == TestToolConstants.TestToolSource ? Common.Constants.MfcAllDestinations.AKL01 : source, _shipmentTransportOrder.Destination);
db.Add(ordersHost);
//Only for Etra boxes we transmitt the order here. The other orders are started at the checkResult Telegram.
if (ordersHost.Le.LeType.Name == LeTypeName.EtraBox)
{
//Send Tord to Old PLC if allowed in Settings
SettingsManager.GetParsedValue(SettingNames.SendTordToOldPlc, out bool sendTord, false, true);
if (sendTord)
{
SendToOldPlcService.SendTord(ordersHost.LeNo, ordersHost.Destination.Split('/').ToList());
}
//We set the Status to transmitted here because we have already sent the telegram and we don't want ConveyorDispo to start those orders (OrdersConveyor is not needed, as there will be no feedback from PLC)
ordersHost.ForceSetStatusTransmitted();
//The EtraBox order will be closed as soon as we get the Departure message from WMS
}
db.SaveChanges();
}
}
}

View File

@@ -0,0 +1,219 @@
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");
}
}
}
}
}

View File

@@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by HostInterfaceConfigurator Version 17.2022.322.1138
// Generated at 28.03.2022 09:44:04 (Universal Time)
//
// This file can be changed to adapt it to project needs.
// If any file is changed, do not run HostInterfaceConfigurator with answer "Yes"
// to dialog question "Do you want to overwrite existing files?"
// Questions and proposals please address to "StoreWare Development Team"
// </auto-generated>
//-----------------------------------------------------------------------------------------
using System;
using Gebhardt.StoreWare.WcsWms.InterfaceWcsWms.Interfaces;
using Gebhardt.StoreWare.WcsWms.InterfaceWcsWms.Models;
using Gebhardt.StoreWare.WcsWms.InterfaceWcsWms.Services;
using Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.Interfaces;
using Gebhardt.Shared;
using Gebhardt.StoreWare.WcsWms.Constants;
using Gebhardt.StoreWare.Wcs.Common.DbAccess;
namespace Gebhardt.StoreWare.Wcs.HostBooking.InterfaceWcsWms.MessageImplementation
{
public partial class UnsupportedHostMessageHandler : IHandleRecord<UnsupportedHostMessage>
{
private readonly IWcsDbContextFactory _dbContextFactory;
private readonly IHostMessageFromWmsService _serviceFromWms;
private readonly IHostMessageToWmsService _serviceToWms;
public UnsupportedHostMessageHandler(IWcsDbContextFactory dbContextFactory, IHostMessageFromWmsService serviceFromWms, IHostMessageToWmsService serviceToWms)
{
_dbContextFactory = dbContextFactory;
_serviceFromWms = serviceFromWms ?? new HostMessageFromWmsService();
_serviceToWms = serviceToWms ?? new HostMessageToWmsService();
}
public bool Handle(UnsupportedHostMessage message)
{
message.Handle();
throw new Exception(message.ErrorInterface ?? "UnsupportedHostMessage - Wrong message type");
//using IWcsDbContext db = _dbContextFactory.GetDbContext();
//TODO - use custom code hier
throw new NotImplementedException();
}
}
}