refactor: migrate project structure by reorganizing realization code snippets into documentation and analysis categories.
This commit is contained in:
BIN
03_Realisierung/OrdersHost Datenmodell/.DS_Store
vendored
Normal file
BIN
03_Realisierung/OrdersHost Datenmodell/.DS_Store
vendored
Normal file
Binary file not shown.
501
03_Realisierung/OrdersHost Datenmodell/OrdersHost.cs
Normal file
501
03_Realisierung/OrdersHost Datenmodell/OrdersHost.cs
Normal file
@@ -0,0 +1,501 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Gebhardt.DbAccess.Base;
|
||||
using Gebhardt.Shared;
|
||||
using Gebhardt.Shared.DbAccess;
|
||||
using Gebhardt.StoreWare.Wcs.Common.Application.TransportHandling.Interfaces;
|
||||
using Gebhardt.StoreWare.Wcs.Common.DbAccess.Factories;
|
||||
using Gebhardt.StoreWare.Wcs.Common.DbAccess.Model.Enums;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
namespace Gebhardt.StoreWare.Wcs.Common.DbAccess.Model;
|
||||
|
||||
public class OrdersHost : AutoIncrementEntity
|
||||
{
|
||||
private Le _le;
|
||||
|
||||
private ICollection<OrdersConveyor> _ordersConveyor;
|
||||
|
||||
private ICollection<OrdersMiniload> _ordersMiniload;
|
||||
|
||||
private ICollection<ResourceList> _resources;
|
||||
|
||||
internal OrdersHost(TransportOrderType type, string leNo, string source, string destination, int priority, int? idOrderWms, int? idOrderWmsHead, int? idOrderWmsPos, OrderTypeWms? typeWms)
|
||||
{
|
||||
Type = type;
|
||||
LeNo = leNo;
|
||||
Source = source;
|
||||
Destination = destination;
|
||||
Priority = priority;
|
||||
IdOrderWms = idOrderWms;
|
||||
IdOrderWmsHead = idOrderWmsHead;
|
||||
IdOrderWmsPos = idOrderWmsPos;
|
||||
TypeWms = typeWms;
|
||||
OrdersConveyor = new List<OrdersConveyor>();
|
||||
OrdersMiniload = new List<OrdersMiniload>();
|
||||
Resources = new List<ResourceList>();
|
||||
}
|
||||
|
||||
private OrdersHost()
|
||||
{
|
||||
}
|
||||
|
||||
private ILazyLoader LazyLoader { get; set; }
|
||||
|
||||
public string LeNo { get; private set; }
|
||||
|
||||
public Le Le
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _le);
|
||||
private set => _le = value;
|
||||
}
|
||||
|
||||
public TransportOrderType Type { get; private set; }
|
||||
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// the (possibly gross) destination for the Le: a storage area, a work place, etc.
|
||||
/// </summary>
|
||||
public string Destination { get; set; }
|
||||
|
||||
public string HostDestination { get; set; }
|
||||
|
||||
public TransportOrderStatus Status { get; private set; } = TransportOrderStatus.Initial;
|
||||
|
||||
public int? IdOrderWmsHead { get; private set; }
|
||||
|
||||
public int? IdOrderWms { get; private set; }
|
||||
|
||||
public int? IdOrderWmsPos { get; private set; }
|
||||
|
||||
// Currently not used at ETRA
|
||||
public int Priority { get; set; }
|
||||
|
||||
public DateTime? PriorityDate { get; set; }
|
||||
|
||||
public DateTime? StartTime { get; private set; }
|
||||
|
||||
public string Info { get; set; }
|
||||
|
||||
public OrderTypeWms? TypeWms { get; }
|
||||
|
||||
public string Error { get; internal set; }
|
||||
|
||||
public bool IsEmptyLeRequest { get; set; }
|
||||
|
||||
// Used by sequencer to know what order to send out boxes in.
|
||||
public int? SequenceWms { get; set; }
|
||||
|
||||
public bool? IsDirectPicking { get; set; }
|
||||
|
||||
//Used in deadlock situations when the same box is used in multiple Sequencers
|
||||
public bool? IsStolen { get; set; }
|
||||
|
||||
public DateTime? SequencerRetrievalTime { get; set; }
|
||||
|
||||
// Used to signal ConveyorDispo that a depature request has been made by HostBooking (DepatureNotificationHandler)
|
||||
public bool? DepartureFlag { get; set; }
|
||||
|
||||
// Used to store the location of a DepartureNotification handled by HostBooking (DepartureNotificationHandler)
|
||||
public string? DepartureLocation { get; set; }
|
||||
|
||||
public ICollection<OrdersMiniload> OrdersMiniload
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _ordersMiniload);
|
||||
set => _ordersMiniload = value;
|
||||
}
|
||||
|
||||
public ICollection<OrdersConveyor> OrdersConveyor
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _ordersConveyor);
|
||||
set => _ordersConveyor = value;
|
||||
}
|
||||
|
||||
public ICollection<ResourceList> Resources
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _resources);
|
||||
set => _resources = value;
|
||||
}
|
||||
|
||||
//Todo-Job: I don't like that the order is directly transmitted and no Tord is sent.
|
||||
public OrdersConveyor StartConveyorOrderToNextDestination(IDestinationProperties newDestination = null, string reasonforredirect = null)
|
||||
{
|
||||
if (Status == TransportOrderStatus.InDestinationZone && newDestination is { BuffersEmptyLe: true })
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot start {nameof(OrdersConveyor)} to next destination ({newDestination.Name}) as the {nameof(OrdersHost)} has already arrived.");
|
||||
}
|
||||
OrdersConveyor openOrder = OrdersConveyor.SingleOrDefault(oc => TransportOrderStatusGroups.Open.Contains(oc.Status));
|
||||
if (openOrder != null)
|
||||
{
|
||||
openOrder.HandleFinished(newDestination);
|
||||
}
|
||||
|
||||
OrdersConveyor followingOrder = OrdersConveyorFactory.GetInstance(this).InitialForOrdersHost(openOrder?.Destination, newDestination?.Name);
|
||||
|
||||
followingOrder.Transmit(reasonforredirect);
|
||||
return followingOrder;
|
||||
}
|
||||
|
||||
public void Redirect(IDestinationProperties newDestination = null, string reasonForRedirect = null)
|
||||
{
|
||||
if (newDestination != null && newDestination.Name != Destination)
|
||||
{
|
||||
OrdersConveyor openOrder = OrdersConveyor.SingleOrDefault(oc => TransportOrderStatusGroups.Open.Contains(oc.Status));
|
||||
if (openOrder != null)
|
||||
{
|
||||
openOrder.Cancel($"Redirected to {newDestination.Name}");
|
||||
UpdateResources(TransportOrderStatus.Cancelled, null);
|
||||
}
|
||||
Destination = newDestination.Name;
|
||||
Info = reasonForRedirect;
|
||||
OrdersConveyor followingOrder = OrdersConveyorFactory.GetInstance(this).InitialForOrdersHost(openOrder?.Destination, newDestination.Name);
|
||||
followingOrder.Transmit();
|
||||
}
|
||||
}
|
||||
|
||||
public OrdersHost Reinitialize(string info)
|
||||
{
|
||||
Status = TransportOrderStatus.Initial;
|
||||
Info = info;
|
||||
StartTime = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrdersHost Postpone(IDestinationProperties destination, string info)
|
||||
{
|
||||
if (!TransportOrderStatusGroups.Waiting.Contains(Status))
|
||||
{
|
||||
throw new InvalidOperationException("Only orders that have not started yet can be postponed.");
|
||||
}
|
||||
if (!destination.BuffersEmptyLe)
|
||||
{
|
||||
Reinitialize(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cancel(string.Empty, info);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrdersConveyor TransportToNio(string error)
|
||||
{
|
||||
Error = error;
|
||||
OrdersConveyor nioTransport = OrdersConveyor?.FirstOrDefault();
|
||||
if (nioTransport == null)
|
||||
{
|
||||
nioTransport = OrdersConveyorFactory.GetInstance(this).PendingForOrdersHost(error: error);
|
||||
}
|
||||
nioTransport.Transmit(error);
|
||||
return nioTransport;
|
||||
}
|
||||
|
||||
public OrdersHost Schedule(string source = null, string info = null)
|
||||
{
|
||||
if (TransportOrderStatusGroups.Waiting.Contains(Status))
|
||||
{
|
||||
Status = TransportOrderStatus.Pending;
|
||||
Info = info;
|
||||
if (source != null)
|
||||
{
|
||||
Source = source;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Write(LogLevel.Error, $"cannot schedule due to Status={Status}; {this} ");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set the OrdersHost to initial - if it's Status is InProgress or Transmitted
|
||||
/// </summary>
|
||||
/// <param name="info">informal reason</param>
|
||||
/// <returns>true if rescheduled</returns>
|
||||
public bool Reschedule(string info = null, string source = null)
|
||||
{
|
||||
if (Status != TransportOrderStatus.InProgress && Status != TransportOrderStatus.Transmitted)
|
||||
{
|
||||
Log.Write(LogLevel.Error, $"cannot reschedule due to Status={Status}; {this} ");
|
||||
return false;
|
||||
}
|
||||
Status = TransportOrderStatus.Initial;
|
||||
Info = info;
|
||||
if (source != null) { Source = source; }
|
||||
Log.Write(LogLevel.Info, $"Rescheduled {this}");
|
||||
return true;
|
||||
}
|
||||
|
||||
public OrdersHost Start()
|
||||
{
|
||||
if (TransportOrderStatusGroups.Waiting.Contains(Status))
|
||||
{
|
||||
Status = TransportOrderStatus.InProgress;
|
||||
StartTime = DBDateTime.Now;
|
||||
DepartureFlag = false;
|
||||
DepartureLocation = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void ManageResources()
|
||||
{
|
||||
if (!(Resources ??= new List<ResourceList>()).All(r => r.Status == TransportOrderStatus.Cancelled || r.Status == TransportOrderStatus.Finished) &&
|
||||
Resources.Count != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Is there an old resource that we need to reuse? (Primary key).
|
||||
ResourceList oldResource = Resources.FirstOrDefault(r => r.OrdersHostId == Id && r.Name == Destination);
|
||||
if (oldResource != null)
|
||||
{
|
||||
oldResource.Status = Status;
|
||||
}
|
||||
// If not create new.
|
||||
else
|
||||
{
|
||||
Resources.Add(new ResourceList
|
||||
{
|
||||
OrdersHostId = Id,
|
||||
LeNo = LeNo,
|
||||
Name = Destination,
|
||||
Status = Status
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void AddResourceEntry(TransportOrderStatus status, string destination)
|
||||
{
|
||||
// Is there an old resource that we need to reuse? (Primary key).
|
||||
ResourceList oldResource = Resources.FirstOrDefault(r => r.OrdersHostId == Id && r.Name == destination);
|
||||
if (oldResource != null)
|
||||
{
|
||||
oldResource.Status = status;
|
||||
}
|
||||
// If not create new.
|
||||
else
|
||||
{
|
||||
Resources.Add(new ResourceList
|
||||
{
|
||||
OrdersHostId = Id,
|
||||
LeNo = LeNo,
|
||||
Name = destination,
|
||||
Status = status
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void FinishResources(string destination)
|
||||
{
|
||||
// Is there an old resource that we need to reuse? (Primary key)
|
||||
List<ResourceList> oldResource = Resources.Where(r => r.Name == destination).ToList();
|
||||
foreach (ResourceList res in oldResource)
|
||||
{
|
||||
res.Status = TransportOrderStatus.Finished;
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelResources(string destination)
|
||||
{
|
||||
List<ResourceList> oldResource = Resources.Where(r => r.Name == destination).ToList();
|
||||
foreach (ResourceList res in oldResource)
|
||||
{
|
||||
Log.Write(LogLevel.Info, $"Cancelling previously assigned resource for Le {LeNo} to destination {destination}");
|
||||
res.Status = TransportOrderStatus.Cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
public OrdersHost EnterZone(IDestinationProperties destination)
|
||||
{
|
||||
if (!(TransportOrderStatusGroups.Active.Contains(Status) || Status == TransportOrderStatus.InSequencer))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
Status = TransportOrderStatus.InDestinationZone;
|
||||
UpdateResources(TransportOrderStatus.InDestinationZone, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the status to <code>InDestinationZone</code>, update the resources and register the Le at the destination (if
|
||||
/// known)
|
||||
/// </summary>
|
||||
/// <param name="destinationService"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public OrdersHost Arrive(IDestinationService destinationService)
|
||||
{
|
||||
if (TransportOrderStatusGroups.Waiting.Contains(Status))
|
||||
{
|
||||
throw new InvalidOperationException("Order has to start before it can arrive.");
|
||||
}
|
||||
|
||||
if (TransportOrderStatusGroups.Complete.Contains(Status))
|
||||
{
|
||||
throw new InvalidOperationException("Order can not arrive if it is already finished.");
|
||||
}
|
||||
|
||||
if (TransportOrderStatusGroups.Active.Contains(Status))
|
||||
{
|
||||
Status = TransportOrderStatus.InDestinationZone;
|
||||
destinationService?.SetArrived(LeNo, Destination);
|
||||
|
||||
UpdateResources(TransportOrderStatus.InDestinationZone, null);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// finish this order, related OrdersMiniload, Orders Conveyor and clear the resources
|
||||
/// </summary>
|
||||
public void Finish()
|
||||
{
|
||||
OrdersConveyor.ToList().ForEach(oc =>
|
||||
{
|
||||
if (TransportOrderStatusGroups.Open.Contains(oc.Status))
|
||||
{
|
||||
oc.HandleFinished();
|
||||
using IWcsDbContext db = new WcsDbContextFactory().GetDbContext();
|
||||
ConveyorTelegrams.SendTordDeleteEtra(db, oc.LeNo);
|
||||
db.SaveChanges();
|
||||
}
|
||||
});
|
||||
OrdersMiniload.ToList().ForEach(om =>
|
||||
{
|
||||
if (TransportOrderStatusGroups.Open.Contains(om.Status))
|
||||
{
|
||||
om.HandleFinished();
|
||||
}
|
||||
});
|
||||
Status = TransportOrderStatus.Finished;
|
||||
UpdateResources(TransportOrderStatus.Finished, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel this order, related OrdersMiniload, Orders Conveyor and clear the resources
|
||||
/// </summary>
|
||||
public void Cancel(string error, string info, bool cancelOrdersMiniload = true)
|
||||
{
|
||||
OrdersConveyor.ToList().ForEach(oc =>
|
||||
{
|
||||
if (TransportOrderStatusGroups.Open.Contains(oc.Status))
|
||||
{
|
||||
oc.Cancel(error);
|
||||
}
|
||||
});
|
||||
if (cancelOrdersMiniload)
|
||||
{
|
||||
OrdersMiniload.ToList().ForEach(om =>
|
||||
{
|
||||
if (TransportOrderStatusGroups.Open.Contains(om.Status))
|
||||
{
|
||||
om.Cancel(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
Status = TransportOrderStatus.Cancelled;
|
||||
Error = error;
|
||||
Info = info;
|
||||
UpdateResources(TransportOrderStatus.Cancelled, null);
|
||||
}
|
||||
|
||||
public OrdersMiniload GetPendingOrdersMiniload()
|
||||
{
|
||||
return OrdersMiniload?.SingleOrDefault(o => o.Status == TransportOrderStatus.Pending);
|
||||
}
|
||||
|
||||
public OrdersMiniload GetOpenOrdersMiniload()
|
||||
{
|
||||
return OrdersMiniload?.FirstOrDefault(o => TransportOrderStatusGroups.Open.Contains(o.Status));
|
||||
}
|
||||
|
||||
public OrdersMiniload GetActiveOrdersMiniload()
|
||||
{
|
||||
return OrdersMiniload?.SingleOrDefault(o => TransportOrderStatusGroups.Active.Contains(o.Status));
|
||||
}
|
||||
|
||||
public OrdersConveyor GetActiveOrdersConveyor()
|
||||
{
|
||||
return OrdersConveyor?.SingleOrDefault(o => TransportOrderStatusGroups.Active.Contains(o.Status));
|
||||
}
|
||||
|
||||
public void UpdateResources(TransportOrderStatus resourceListStatus, List<ResourceList> occupiedBySameLeButDifferentOrder)
|
||||
{
|
||||
//If a OrdersHost is Finished or Cancelled all ResourceList for this OH are affected, for other status only entries with same Destination
|
||||
Resources
|
||||
.Where(r => !TransportOrderStatusGroups.Complete.Contains(r.Status) && (r.Name == Destination || resourceListStatus == TransportOrderStatus.Finished || resourceListStatus == TransportOrderStatus.Cancelled))
|
||||
.ToList()
|
||||
.ForEach(r => r.Status = resourceListStatus);
|
||||
occupiedBySameLeButDifferentOrder?.ForEach(r => r.Status = TransportOrderStatus.Cancelled);
|
||||
}
|
||||
|
||||
public void UpdateSpecificResource(TransportOrderStatus resourceListStatus, string destination)
|
||||
{
|
||||
ResourceList oldResource = Resources.FirstOrDefault(r => r.OrdersHostId == Id && r.Name == destination);
|
||||
if (oldResource == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldResource.Status = resourceListStatus;
|
||||
}
|
||||
}
|
||||
public OrdersHost ReplaceNextEmptyLe(Le le)
|
||||
{
|
||||
if (!LeType.EmptyLeTypeNames.Contains(Le.Type))
|
||||
{
|
||||
throw new ArgumentException($"Reassigning an LE is only allowed to replace any of {nameof(LeType.EmptyLeTypeNames)}. Current LE: {le.LeNo}");
|
||||
}
|
||||
|
||||
Le = le;
|
||||
ResourceList resource = Resources.SingleOrDefault(r => r.Name == Destination);
|
||||
if (resource != null)
|
||||
{
|
||||
resource.Le = le;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(OrdersHost)}[{nameof(Id)}: {Id}, {nameof(LeNo)}: {LeNo}, {nameof(Type)}: {Type}, {nameof(Source)}: {Source}, {nameof(Destination)}: {Destination}, {nameof(Status)}: {Status}, {nameof(IdOrderWmsHead)}: {IdOrderWmsHead}, {nameof(IdOrderWms)}: {IdOrderWms}, {nameof(IdOrderWmsPos)}: {IdOrderWmsPos}]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the status to InDestinationZone regardless of the previous status. This is ONLY to be used for creating an orders host dummy when we get a no read on the outputs. Otherwise we cannot send an UnloadHuToAgv telegram to unload the board to an AGV.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public OrdersHost ForceSetStatusInDestinationZone()
|
||||
{
|
||||
Status = TransportOrderStatus.InDestinationZone;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrdersHost ForceSetStatusInSequencer()
|
||||
{
|
||||
Status = TransportOrderStatus.InSequencer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrdersHost ForceSetStatusInProgress()
|
||||
{
|
||||
Status = TransportOrderStatus.InProgress;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrdersHost ForceSetStatusTransmitted()
|
||||
{
|
||||
Status = TransportOrderStatus.Transmitted;
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool IsSequencerCancelOrder()
|
||||
{
|
||||
return Source.Contains(WcsNames.SEQ) && Destination == Common.Constants.MfcAllDestinations.StorageLoop2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Gebhardt.DbAccess.Base.Configuration;
|
||||
using Gebhardt.StoreWare.Wcs.Common.DbAccess.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using static Gebhardt.StoreWare.WcsWms.Constants.ModelConstants;
|
||||
|
||||
namespace Gebhardt.StoreWare.Wcs.Common.DbAccess.Configuration;
|
||||
|
||||
public class OrdersHostEntityConfiguration : BaseEntityConfiguration<OrdersHost>
|
||||
{
|
||||
public override void Configure(EntityTypeBuilder<OrdersHost> builder)
|
||||
{
|
||||
base.Configure(builder);
|
||||
|
||||
builder.HasIndex(e => new { e.LeNo, e.Status }, "I1_OrdersHost");
|
||||
|
||||
builder.HasIndex(e => new { e.Destination, e.Status }, "I2_OrdersHost");
|
||||
|
||||
builder.HasIndex(e => new { e.Type, e.Status }, "I3_OrdersHost");
|
||||
|
||||
builder.Property(e => e.Destination).IsRequired().HasMaxLength(OrderSourceDestLength);
|
||||
|
||||
builder.Property(e => e.Error).HasMaxLength(ErrorTextLength);
|
||||
|
||||
builder.Property(e => e.IdOrderWms);
|
||||
|
||||
builder.Property(e => e.IdOrderWmsHead);
|
||||
|
||||
builder.Property(e => e.IdOrderWmsPos);
|
||||
|
||||
builder.Property(e => e.DepartureFlag);
|
||||
|
||||
builder.Property(e => e.DepartureLocation);
|
||||
|
||||
builder.Property(e => e.Info).HasMaxLength(InfoTextLength);
|
||||
|
||||
builder.Property(e => e.Source).IsRequired().HasMaxLength(OrderSourceDestLength);
|
||||
|
||||
builder.Property(e => e.Status)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(e => e.Type)
|
||||
.IsRequired();
|
||||
|
||||
|
||||
builder.Property(e => e.LeNo).IsRequired().HasMaxLength(LeNoLength);
|
||||
|
||||
builder.HasOne(e => e.Le).WithMany().HasForeignKey(e => e.LeNo).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasMany(e => e.Resources).WithOne(e => e.OrdersHost).HasForeignKey(e => e.OrdersHostId).IsRequired();
|
||||
}
|
||||
}
|
||||
241
03_Realisierung/OrdersHost Datenmodell/OrdersHostQueries.cs
Normal file
241
03_Realisierung/OrdersHost Datenmodell/OrdersHostQueries.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Gebhardt.StoreWare.Wcs.Common.Dao;
|
||||
using Gebhardt.StoreWare.Wcs.Common.DbAccess.Model;
|
||||
using Gebhardt.StoreWare.Wcs.Common.DbAccess.Model.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using static Gebhardt.StoreWare.Wcs.Common.Constants;
|
||||
|
||||
namespace Gebhardt.StoreWare.Wcs.Common.DbAccess.Queries
|
||||
{
|
||||
public static class OrdersHostQueries
|
||||
{
|
||||
public static IQueryable<OrdersHost> ByStatus(this IQueryable<OrdersHost> entity, params TransportOrderStatus[] states)
|
||||
{
|
||||
return entity.Where(o => states.Contains(o.Status));
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> ByType(this IQueryable<OrdersHost> entity, params TransportOrderType[] types)
|
||||
{
|
||||
return entity.Where(o => types.Contains(o.Type));
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> ByLeNo(this IQueryable<OrdersHost> entity, string leNo)
|
||||
{
|
||||
return entity.Where(o => o.LeNo == leNo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// select entities with one of the given destinations
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<OrdersHost> ByDestination(this IQueryable<OrdersHost> entity, IEnumerable<string> destinations)
|
||||
{
|
||||
return entity.Where(o => destinations.Contains(o.Destination));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// select entities which hs not one of the given destinations
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<OrdersHost> ExcludeDestination(this IQueryable<OrdersHost> entity, IEnumerable<string> destinations)
|
||||
{
|
||||
return entity.Where(o => !destinations.Contains(o.Destination));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// select entities with the given destination
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<OrdersHost> ByDestination(this IQueryable<OrdersHost> entity, string destination)
|
||||
{
|
||||
return entity.Where(o => destination == o.Destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// searches for OH
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="leNo"></param>
|
||||
/// <returns></returns>
|
||||
public static OrdersHost ActiveByLeNo(this IQueryable<OrdersHost> entity, string leNo)
|
||||
{
|
||||
return entity
|
||||
.ByLeNo(leNo)
|
||||
.SingleOrDefault(o => o.Status == TransportOrderStatus.InProgress || o.Status == TransportOrderStatus.InDestinationZone || o.Status == TransportOrderStatus.InSequencer);
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> AllActiveByLeNo(this IQueryable<OrdersHost> entity, string leNo)
|
||||
{
|
||||
return entity
|
||||
.ByLeNo(leNo)
|
||||
.Where(o => o.Status == TransportOrderStatus.InProgress || o.Status == TransportOrderStatus.InDestinationZone || o.Status == TransportOrderStatus.InSequencer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// find - if exists open orders host entries (Status: Initial, InProgress, InDestinationZone, Pending)
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="leNo">the le number</param>
|
||||
/// <returns>null or an open orders host</returns>
|
||||
public static IQueryable<OrdersHost> OpenByLeNo(this IQueryable<OrdersHost> entity, string leNo)
|
||||
{
|
||||
return entity
|
||||
.Where(o => o.LeNo == leNo)
|
||||
.Open()
|
||||
//Better include this here in case one of the initial orders is started by that (done in many places)
|
||||
.ApplyWmsOrdering();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// find - open orders host entries (Status: Initial, InProgress, InDestinationZone, Pending)
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns>null or an open orders host</returns>
|
||||
public static IQueryable<OrdersHost> Open(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Where(o => TransportOrderStatusGroups.Open.Contains(o.Status));
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> Active(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Where(o => TransportOrderStatusGroups.Active.Contains(o.Status));
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> ActivePendingOrInSequecer(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Where(o => TransportOrderStatusGroups.Active.Contains(o.Status) || o.Status == TransportOrderStatus.InSequencer || o.Status == TransportOrderStatus.Pending);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all destinations for which there are orders host existing in any state
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetAllDestinations(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Select(oh => oh.Destination).Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all destinations for which there are orders host existing in the given states
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetAllDestinations(this IQueryable<OrdersHost> entity, params TransportOrderStatus[] states)
|
||||
{
|
||||
return entity.Where(oh => states.Contains(oh.Status)).Select(oh => oh.Destination).Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all destinations for the orders host (maybe precede by an "Open()"!)
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetAllDestinations(this IQueryable<OrdersHost> entity, IEnumerable<string> destinations)
|
||||
{
|
||||
return entity.Where(oh => destinations.Contains(oh.Destination)).Select(oh => oh.Destination).Distinct().ToList();
|
||||
}
|
||||
|
||||
public static IQueryable<OrderCountByDay> GetCountByDate(this IQueryable<OrdersHost> entity, TransportOrderType orderType, IEnumerable<DateTime> dates)
|
||||
{
|
||||
return entity.Where(oh => oh.Status == TransportOrderStatus.Finished && oh.Created.Date > dates.First().Date && oh.Type == orderType).GroupBy(oh => oh.Created.Date).OrderBy(g => g.Key).Select(r => new OrderCountByDay(r.Count(), r.Key));
|
||||
}
|
||||
|
||||
public static IQueryable<OrderCountByDestination> GetCountByDestination(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
// This SQL is translated into a Lambda expression
|
||||
DateTime today = DateTime.Now.Date;
|
||||
DateTime yesterday = today.AddDays(-1);
|
||||
return entity.Where(oh => oh.Status == TransportOrderStatus.Finished && oh.Created.Date >= yesterday && oh.Type == TransportOrderType.TransportHost).GroupBy(oh => oh.Destination).OrderBy(g => g.Key).Select(r => new OrderCountByDestination(
|
||||
r.Key,
|
||||
r.Sum(d => d.Created.Date == today ? 1 : 0),
|
||||
r.Sum(d => d.Created.Date == yesterday ? 1 : 0)));
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> ExcludeNextEmpty(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Where(o => o.LeNo != LeTypeName.NextEmptyMiniloadSmall.ToString() && o.LeNo != LeTypeName.NextEmptyMiniloadBig.ToString());
|
||||
}
|
||||
|
||||
public static IQueryable<OrdersHost> OnlyNextEmpty(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Where(o => o.LeNo == LeTypeName.NextEmptyMiniloadSmall.ToString() || o.LeNo == LeTypeName.NextEmptyMiniloadBig.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special WMS ordering that takes the common Sequencer Retrieval Time into account
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="db"></param>
|
||||
/// <returns></returns>
|
||||
public static IOrderedQueryable<OrdersHost> ApplyWmsOrderingSequencerRetrievalTime(this IQueryable<OrdersHost> entity,
|
||||
IWcsDbContext db)
|
||||
{
|
||||
var query = entity
|
||||
.GroupJoin(
|
||||
db.OrdersHost
|
||||
.GroupBy(xx => xx.IdOrderWmsHead)
|
||||
.Select(g => new
|
||||
{
|
||||
IdOrderWmsHead = g.Key,
|
||||
SequencerRetrievalTime = g.Min(y => y.SequencerRetrievalTime)
|
||||
}),
|
||||
o => o.IdOrderWmsHead,
|
||||
m => m.IdOrderWmsHead,
|
||||
(o, m) => new { o, m }
|
||||
)
|
||||
.SelectMany(x => x.m.DefaultIfEmpty(), (x, m) => new { x.o, m })
|
||||
.OrderByDescending(x => x.o.IsStolen)
|
||||
.ThenByDescending(x => x.o.IsDirectPicking)
|
||||
.ThenByDescending(x => x.m.SequencerRetrievalTime != null)
|
||||
.ThenBy(x => x.m.SequencerRetrievalTime)
|
||||
.ThenBy(x => x.o.Created)
|
||||
.Select(x => x.o);
|
||||
return (IOrderedQueryable<OrdersHost>) query;
|
||||
}
|
||||
|
||||
public static IOrderedQueryable<OrdersHost> ApplyWmsOrdering(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
// Only order by Created, as WMS anyways only releases a limited number of orders. This saves us from running into dealocks.
|
||||
//Sequencer RetrievalTime is set when box is retrieved from sequencer.
|
||||
return entity
|
||||
.OrderByDescending(o => o.IsStolen)
|
||||
.ThenByDescending(o => o.IsDirectPicking)
|
||||
.ThenByDescending(o => o.SequencerRetrievalTime != null)
|
||||
.ThenBy(o => o.SequencerRetrievalTime)
|
||||
.ThenBy(o => o.Created);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exclude all OHs where the LE is located in the sequencer, unless this order is a cancel order
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<OrdersHost> ExcludeOrdersInSequencer(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
//The comented orders are started in Seq_Dispo
|
||||
return entity.Where(o => !(o.Le.Status == LeStatus.InStorage && o.Le.Aisle.Type == AisleType.Sequencer) /*|| (o.Source.Contains(WcsNames.SEQ) && o.Destination == MfcAllDestinations.StorageLoop2)*/);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter by sequenceorders that has been cancelled
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<OrdersHost> ByCancelledSequencerOrder(this IQueryable<OrdersHost> entity)
|
||||
{
|
||||
return entity.Where(o => o.Source.Contains(WcsNames.SEQ) && o.Destination == MfcAllDestinations.StorageLoop2);
|
||||
}
|
||||
/// <summary>
|
||||
/// Filters by all orders that have been marked for departure by HostBooking (DepartureNotificationHandler)
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<OrdersHost> IsDepartureReady(this IQueryable<OrdersHost> entity) {
|
||||
return entity.Where(o => o.DepartureLocation != null && o.DepartureFlag == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user