public static void AddSimulateCommand(this CommandLineApplication app, IConfiguration configuration, IServiceProvider serviceProvider) { app.Command("sim", cmd => { cmd.OnExecute(() => { Console.WriteLine("Specify a subcommand"); cmd.ShowHelp(); return(1); }); cmd.Command("posting", postingCmd => { postingCmd.Description = "Will convert all pending Olma PostRequests to Ltms Bookings."; //var all = postingCmd.Option("a", "Convert all Posting Requests", CommandOptionType.NoValue, config => config.LongName = "all"); //var id = postingCmd.Argument("id", "Id of the posting request to convert"); //var database = postingCmd.Argument<Databases>("database-name", "Name of the database. Valid options are: olma, ltms") //.Accepts(configure => //{ // configure.Enum<Databases>(true); //}) //.IsRequired(); postingCmd.OnExecuteAsync(async(token) => { var mapper = serviceProvider.GetService <IMapper>(); var syncService = serviceProvider.GetService <ISyncService>(); var olmaRepo = serviceProvider.GetService <IRepository <Olma.PostingRequest> >(); var pendingRequests = olmaRepo.FindByCondition(i => i.Status == PostingRequestStatus.Pending) .IgnoreQueryFilters().Where(a => !a.IsDeleted) .ProjectTo <PostingRequestsCreateRequest>(mapper.ConfigurationProvider).ToList(); if (pendingRequests.Count > 0) { var result = await syncService.CreateLtmsBookings(pendingRequests); if (result) { foreach (var request in pendingRequests) { var record = olmaRepo .FindByCondition(r => r.RefLtmsTransactionId == request.RefLtmsTransactionId) .IgnoreQueryFilters().SingleOrDefault(); if (record != null) { record.Status = PostingRequestStatus.Confirmed; olmaRepo.Update(record); } } olmaRepo.Save(); Console.WriteLine( $"Converterd all Olma PostingRequests to Ltms Bookings successfully."); } else { Console.WriteLine( $"Something has gone wrong, no Olma PostingRequests have been converted to Ltms Bookings."); } } else { Console.WriteLine($"Nothing to do"); } }); }); cmd.Command("transport", transportCmd => { transportCmd.Description = "Will accept a bid for all trasports with status 'Requested' and that have active bids."; //var all = postingCmd.Option("a", "Convert all Posting Requests", CommandOptionType.NoValue, config => config.LongName = "all"); //var id = postingCmd.Argument("id", "Id of the posting request to convert"); //var database = postingCmd.Argument<Databases>("database-name", "Name of the database. Valid options are: olma, ltms") //.Accepts(configure => //{ // configure.Enum<Databases>(true); //}) //.IsRequired(); transportCmd.OnExecuteAsync(async(token) => { var olmaTransportRepo = serviceProvider.GetService <IRepository <Dal.Models.Transport> >(); var transportService = serviceProvider.GetService <ITransportOfferingsService>(); var transportsToAccept = olmaTransportRepo.FindAll() .IgnoreQueryFilters() .Include(i => i.Bids) .Where(i => i.Status == Dal.Models.TransportStatus.Requested && i.Bids.Any(i => i.Status == Common.Enumerations.TransportBidStatus.Active)) .ToList(); foreach (var transport in transportsToAccept) { var bidToAccept = transport.Bids.First(i => i.Status == Common.Enumerations.TransportBidStatus.Active); await transportService.AcceptBid(transport.Id, new Contracts.Models.TransportOfferingBidAcceptRequest() { BidId = bidToAccept.Id }); } Console.WriteLine( $"Accepted bids for all transfers with status 'Requested' and that had active bids."); }); }); cmd.Command("ordermatch", orderMatchCmd => { orderMatchCmd.Description = "Will create a orderMatch of to given OrderIds."; var optionSupply = orderMatchCmd.Option <int>("-s|--supply <OrderId>", "Required. The Id of the supply order." , CommandOptionType.SingleValue) .Accepts(o => o.Range(1, 99999)) .IsRequired(); var optionDemand = orderMatchCmd.Option <int>("-d|--demand <OrderId>", "Required. The Id of the demand order." , CommandOptionType.SingleValue) .Accepts(o => o.Range(1, 99999)) .IsRequired(); orderMatchCmd.OnExecuteAsync(async(token) => { int supplyId = optionSupply.ParsedValue; int demandId = optionDemand.ParsedValue; Console.WriteLine( $"Create Order Match for OrderId:{supplyId} (Supply) and OrderId:{demandId} (Demand)"); var orderRepo = serviceProvider.GetService <IRepository <Olma.Order> >(); var supplyOrder = orderRepo.FindByCondition(o => o.Id == supplyId).IgnoreQueryFilters() .AsNoTracking().FirstOrDefault(); var demandOrder = orderRepo.FindByCondition(o => o.Id == demandId).IgnoreQueryFilters() .AsNoTracking().FirstOrDefault(); var supplyOrderGroupId = supplyOrder.GroupId; var demandOrderGroupId = demandOrder.GroupId; if (supplyOrderGroupId == null || supplyOrderGroupId == 0 || demandOrderGroupId == null || demandOrderGroupId == 0) { Console.WriteLine($"Couldn't find OrderGroups"); return; } DateTime demandFulfillmentDate; DateTime supplyFulfillmentDate; try { GetFulfillmentDates(supplyOrder, demandOrder, out supplyFulfillmentDate, out demandFulfillmentDate); } catch (Exception e) { Console.WriteLine( $"Error searching for matching fulfillment Dates on weekday: {e.Message}"); return; } var orderMatchService = serviceProvider.GetService <IOrderMatchesService>(); var createRequest = new OrderMatchesCreateRequest() { // TODO Update to use RowGuids instead //SupplyOrderGroupId = (int) supplyOrderGroupId, //DemandOrderGroupId = (int) demandOrderGroupId, TransportType = OrderTransportType.Self, SelfTransportSide = OrderType.Demand, DemandFulfillmentDateTime = demandFulfillmentDate, SupplyFulfillmentDateTime = supplyFulfillmentDate }; var response = (IWrappedResponse <OrderMatch>)orderMatchService.Create(createRequest).Result; var orderMatchId = response.Data?.Id; if (orderMatchId == null) { Console.WriteLine($"Error while creating OrderMatch"); return; } Console.WriteLine($"OrderMatch Id: {orderMatchId} created"); //Update OrderMatch Status var orderMatchRepo = serviceProvider.GetService <IRepository <Olma.OrderMatch> >(); var orderMatch = orderMatchRepo.GetByKey((int)orderMatchId); orderMatch.Status = OrderMatchStatus.TransportScheduled; Console.WriteLine($"Set OrderMatch.Status to :{nameof(OrderMatchStatus.TransportScheduled)}"); orderMatchRepo.Update(orderMatch); orderMatchRepo.Save(); }); }); cmd.Command("dlqorder", dlqCmd => { dlqCmd.Description = "send message to DLQ"; dlqCmd.OnExecuteAsync(async(token) => await TransferMessageToDlqAsync(OrderQueueName)); }); cmd.Command("dlqpostingrequest", dlqCmd => { dlqCmd.Description = "send message to DLQ"; dlqCmd.OnExecuteAsync(async(token) => await TransferMessageToDlqAsync(PostingRequestQueueName)); }); }); }
public async Task <IWrappedResponse> Create(OrderMatchesCreateRequest request) { #region security // TODO add security #endregion if (request == null || request.DemandOrderRowGuid == Guid.Empty || request.SupplyOrderRowGuid == Guid.Empty) { return(BadRequest <OrderMatch>("DemandOrderRowGuid or SupplyOrderRowGuid required")); } Olma.OrderMatch orderMatch; var loadCarrierIds = new[] { request.LoadCarrierId, request.BaseLoadCarrierId }.Distinct() .Where(i => i != null).ToArray(); var loadCarrierQuantityPerEurDict = _olmaLoadCarrierRepo.FindAll() .Where(i => loadCarrierIds.Contains(i.Id)) .Include(i => i.Type).FromCache() .ToDictionary(i => i.Id, i => i.Type.QuantityPerEur); var virtualLmsOrders = _olmaOrderRepo .FindAll() .Where(i => i.RefLmsOrderRowGuid == request.DemandOrderRowGuid || i.RefLmsOrderRowGuid == request.SupplyOrderRowGuid) .SelectMany(i => i.Group.Orders) .Where(i => (i.Status == OrderStatus.Pending || i.Status == OrderStatus.Confirmed) && !i.IsDeleted) .Include(i => i.LoadingLocation).ThenInclude(i => i.Address) .Select(i => new Olma.LmsOrder() { RowGuid = i.RefLmsOrderRowGuid, Type = i.Type, // HACK centralize cacluation of load to load carrier quantity AvailableQuantity = i.QuantityType == OrderQuantityType.Load ? 1 * 33 * i.StackHeightMax * loadCarrierQuantityPerEurDict[i.LoadCarrierId] : i.LoadCarrierQuantity.HasValue ? i.LoadCarrierQuantity.Value : 0, StackHeightMin = i.StackHeightMin, StackHeightMax = i.StackHeightMax, FromDate = i.EarliestFulfillmentDateTime, UntilDate = i.LatestFulfillmentDateTime, // TODO rethink if loading location id should be nullable also when coming from lms LoadingLocationId = i.LoadingLocationId.HasValue ? i.LoadingLocationId.Value : 0, LoadingLocation = i.LoadingLocation, OlmaOrderId = i.Id, OlmaOrder = i, LoadCarrierId = i.LoadCarrierId, BaseLoadCarrierId = i.BaseLoadCarrierId, Geblockt = false, SupportsRearLoading = i.SupportsRearLoading, SupportsSideLoading = i.SupportsSideLoading, SupportsJumboVehicles = i.SupportsJumboVehicles, }).ToList(); var orders = _lmsOrderRepo .FindAll() .IgnoreQueryFilters() .Where(i => i.RowGuid == request.DemandOrderRowGuid || i.RowGuid == request.SupplyOrderRowGuid) .Include(i => i.OlmaOrder).ThenInclude(i => i.Group).ThenInclude(i => i.Orders) .Include(i => i.LoadingLocation).ThenInclude(i => i.Address) // the status here MUST NOT include open state as when triggered as we should only match against confirmed orders //.IncludeFilter(og => og.OlmaOrder.Group.Orders.Where(o => (o.Status == OrderStatus.Confirmed || o.Status == OrderStatus.PartiallyMatched) && !o.IsDeleted)) //.IncludeFilter(i => i.LoadingLocation.Address) .ToList(); orders = orders .Concat(virtualLmsOrders) .ToList(); var lmsDemandOrder = orders.FirstOrDefault(o => o.Type == OrderType.Demand); var lmsSupplyOrder = orders.FirstOrDefault(o => o.Type == OrderType.Supply); if (!request.SkipValidation) { Func <Olma.LmsOrder, OrderType, DateTime, bool> validate = (order, orderType, fulfillmentDate) => { return(order.Type == orderType && order.LoadCarrierId == request.LoadCarrierId && ((order.StackHeightMin <= request.LoadCarrierStackHeight && request.LoadCarrierStackHeight <= order.StackHeightMax) // HACK Partial Matching Remove comments when SUpportsPartialMatching is properly set + search is load based //|| (order.SupportsPartialMatching && ( || (( request.LoadCarrierStackHeight <= order.StackHeightMax || (order.StackHeightMin <= request.LoadCarrierStackHeight && request.LoadCarrierStackHeight <= order.StackHeightMax))) ) // no base load carrier specified or matching base load carriers && (!request.BaseLoadCarrierId.HasValue || order.BaseLoadCarrierId == request.BaseLoadCarrierId.Value) && (!request.SupportsRearLoading || order.SupportsRearLoading == request.SupportsRearLoading) && (!request.SupportsSideLoading || order.SupportsSideLoading == request.SupportsSideLoading) && (!request.SupportsJumboVehicles || order.SupportsJumboVehicles == request.SupportsJumboVehicles) && order.FromDate.Value.Date <= fulfillmentDate && fulfillmentDate <= order.UntilDate.Value.Date); }; if (!validate(lmsSupplyOrder, OrderType.Supply, request.SupplyFulfillmentDateTime.Date) || !validate(lmsDemandOrder, OrderType.Demand, request.DemandFulfillmentDateTime.Date)) { return(BadRequest <OrderMatch>( ErrorHandler .Create() .AddMessage(new OrdersNotMatchError()) .GetServiceState())); } if (request.LoadCarrierQuantity > lmsSupplyOrder.AvailableQuantity) { return(BadRequest <OrderMatch>( ErrorHandler .Create() .AddMessage(new QuantityExceededSupplyError()) .GetServiceState())); } if (request.LoadCarrierQuantity > lmsDemandOrder.AvailableQuantity) { return(BadRequest <OrderMatch>( ErrorHandler .Create() .AddMessage(new QuantityExceededDemandError()) .GetServiceState())); } var unavailableOrder = orders.Where(order => order.Id > 0 && !order.IsAvailable).ToList(); if (unavailableOrder.Any()) { // Anmerkung: error werden momentan nur serverseitig gespeichert, nicht jedoch im http response. var error = unavailableOrder.Select(o => o.RowGuid.ToString()).ToArray(); return(BadRequest <OrderMatch>( ErrorHandler .Create() .AddMessage(new AvailableError()) .GetServiceState() , error)); } } orderMatch = Mapper.Map <Olma.OrderMatch>(request); if (request.TransportType == OrderTransportType.ProvidedByOthers) { // TODO add additional status to transport 'Approved' or similar // which signals that this tarsnport has been approved for listing in transport broker in gerneral // on top of that we will show specific approved listings only to cetrain shippers orderMatch.Transport = new Olma.Transport() { ReferenceNumber = await _numberSequencesService.GetTransportNumber(), Status = Olma.TransportStatus.Requested, Type = Olma.TransportType.OrderMatch, // HACK Hardcoded 10 days as planned latest by PlannedLatestBy = DateTime.UtcNow.Date.AddDays(10), ConfirmedLatestBy = DateTime.UtcNow.Date.AddDays(14), RoutedDistance = await _maps.GetRoutedDistance(lmsSupplyOrder.LoadingLocation.Address.GeoLocation, lmsDemandOrder.LoadingLocation.Address.GeoLocation) }; orderMatch.Status = OrderMatchStatus.Pending; } else if (request.TransportType == OrderTransportType.Self) { orderMatch.Status = OrderMatchStatus.TransportScheduled; } // This block deals with permanent availabilities / deliveries // If this is a permananet one we need to geenrate a new Guid // and match against that vs the guid of the permanent if (lmsSupplyOrder.IsPermanent) { orderMatch.RefLmsPermanentAvailabilityRowGuid = orderMatch.RefLmsAvailabilityRowGuid; orderMatch.RefLmsAvailabilityRowGuid = Guid.NewGuid(); } else if (lmsDemandOrder.IsPermanent) { orderMatch.RefLmsPermanentDeliveryRowGuid = orderMatch.RefLmsDeliveryRowGuid; orderMatch.RefLmsDeliveryRowGuid = Guid.NewGuid(); } orderMatch.DigitalCode = await _numberSequencesService.GetDigitalCode(); var orderLoadStatus = orderMatch.Status == OrderMatchStatus.TransportScheduled ? OrderLoadStatus.TransportPlanned : OrderLoadStatus.Pending; var supplyLoadDetails = new Olma.OrderLoadDetail() { PlannedFulfillmentDateTime = request.SupplyFulfillmentDateTime, Status = orderLoadStatus, Address = lmsSupplyOrder.LoadingLocation != null ? lmsSupplyOrder.LoadingLocation.Address : null }; var demandLoadDetails = new Olma.OrderLoadDetail() { PlannedFulfillmentDateTime = request.DemandFulfillmentDateTime, Status = orderLoadStatus, Address = lmsDemandOrder.LoadingLocation != null ? lmsDemandOrder.LoadingLocation.Address : null }; if (lmsSupplyOrder.OlmaOrder != null) { var supplyOrder = lmsSupplyOrder.OlmaOrder.Group.Orders.FirstOrDefault(o => (o.Status == OrderStatus.Pending || o.Status == OrderStatus.Confirmed || o.Status == OrderStatus.PartiallyMatched) && !o.IsDeleted); if (supplyOrder == null) { return(BadRequest <OrderMatch>($"Supply order group out of Sync with LmsOrder, RowGuid: {lmsSupplyOrder.RowGuid}")); } orderMatch.Supply = new Olma.OrderLoad() { Order = supplyOrder, Detail = request.TransportType == OrderTransportType.Self && request.SelfTransportSide == OrderType.Supply ? demandLoadDetails : supplyLoadDetails }; supplyOrder.Status = request.LoadCarrierQuantity >= lmsSupplyOrder.AvailableQuantity ? OrderStatus.Matched : OrderStatus.PartiallyMatched; } if (lmsDemandOrder.OlmaOrder != null) { var demandOrder = lmsDemandOrder.OlmaOrder.Group.Orders.FirstOrDefault(o => (o.Status == OrderStatus.Pending || o.Status == OrderStatus.Confirmed || o.Status == OrderStatus.PartiallyMatched) && !o.IsDeleted); if (demandOrder == null) { return(BadRequest <OrderMatch>($"Demand order group out of Sync with LmsOrder, RowGuid: {lmsSupplyOrder.RowGuid}")); } orderMatch.Demand = new Olma.OrderLoad() { Order = demandOrder, Detail = request.TransportType == OrderTransportType.Self && request.SelfTransportSide == OrderType.Demand ? supplyLoadDetails : demandLoadDetails }; demandOrder.Status = request.LoadCarrierQuantity >= lmsDemandOrder.AvailableQuantity ? OrderStatus.Matched : OrderStatus.PartiallyMatched; } _olmaOrderMatchRepo.Create(orderMatch); var numberOfSavedEntities = 0; while (numberOfSavedEntities == 0) { try { numberOfSavedEntities = _olmaOrderMatchRepo.Save(); } catch (DbUpdateException ex) { // check if the digital code already existed if (ex.InnerException is SqlException innerException && innerException.Number == 2601) { orderMatch.DigitalCode = await _numberSequencesService.GetDigitalCode(); } } } var result = Mapper.Map <Olma.OrderMatch, Contracts.Models.OrderMatch>(orderMatch); return(Created(result)); }
public Task <ActionResult <OrderMatch> > Post([FromBody] OrderMatchesCreateRequest request) { return(this._orderMatchesService.Create(request).Convert <OrderMatch>(this)); }