Beispiel #1
0
        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));
                });
            });
        }
Beispiel #2
0
        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));
 }