public async Task <IEnumerable <WideAvailabilityResult> > GetResult(Guid searchId, AgentContext agent)
        {
            var searchSettings = await _accommodationBookingSettingsService.Get(agent);

            var accommodationDuplicates = await _duplicatesService.Get(agent);

            var supplierSearchResults = await _availabilityStorage.GetResults(searchId, searchSettings.EnabledConnectors);

            return(CombineAvailabilities(supplierSearchResults));

            IEnumerable <WideAvailabilityResult> CombineAvailabilities(IEnumerable <(Suppliers ProviderKey, List <AccommodationAvailabilityResult> AccommodationAvailabilities)> availabilities)
            {
                if (availabilities == null || !availabilities.Any())
                {
                    return(Enumerable.Empty <WideAvailabilityResult>());
                }

                return(availabilities
                       .SelectMany(supplierResults =>
                {
                    var(supplierKey, supplierAvailabilities) = supplierResults;
                    return supplierAvailabilities
                    .Select(pa => (Provider: supplierKey, Availability: pa));
                })
                       .OrderBy(r => r.Availability.Timestamp)
                       .RemoveRepeatedAccommodations()
                       .Select(r =>
                {
                    var(supplier, availability) = r;
                    var supplierAccommodationId = new SupplierAccommodationId(supplier, availability.Accommodation.Id);
                    var hasDuplicatesForCurrentAgent = accommodationDuplicates.Contains(supplierAccommodationId);

                    return new WideAvailabilityResult(availability.Id,
                                                      availability.Accommodation,
                                                      availability.RoomContractSets,
                                                      availability.MinPrice,
                                                      availability.MaxPrice,
                                                      hasDuplicatesForCurrentAgent,
                                                      searchSettings.IsSupplierVisible
                                ? supplier
                                : (Suppliers?)null);
                })
                       .Where(a => a.RoomContractSets.Any()));
            }
        }
Esempio n. 2
0
 public ReportAccommodationDuplicateRequest(SupplierAccommodationId accommodation, List <SupplierAccommodationId> duplicates)
 {
     Accommodation = accommodation;
     Duplicates    = duplicates;
 }
Esempio n. 3
0
        public async Task Start(Guid searchId, AvailabilityRequest request, Suppliers supplier, AgentContext agent, string languageCode,
                                AccommodationBookingSettings searchSettings)
        {
            var supplierConnector = _supplierConnectorManager.Get(supplier);

            try
            {
                _logger.LogProviderAvailabilitySearchStarted($"Availability search with id '{searchId}' on supplier '{supplier}' started");

                await GetAvailability(request, languageCode)
                .Bind(ConvertCurrencies)
                .Map(ApplyMarkups)
                .Map(Convert)
                .Tap(SaveResult)
                .Finally(SaveState);
            }
            catch (Exception ex)
            {
                // TODO: Add sentry error notification
                _logger.LogProviderAvailabilitySearchException(ex);
                var result = ProblemDetailsBuilder.Fail <List <AccommodationAvailabilityResult> >("Server error", HttpStatusCode.InternalServerError);
                await SaveState(result);
            }


            async Task <Result <EdoContracts.Accommodations.Availability, ProblemDetails> > GetAvailability(AvailabilityRequest request,
                                                                                                            string languageCode)
            {
                var saveToStorageTask   = _storage.SaveState(searchId, SupplierAvailabilitySearchState.Pending(searchId), supplier);
                var getAvailabilityTask = supplierConnector.GetAvailability(request, languageCode);
                await Task.WhenAll(saveToStorageTask, getAvailabilityTask);

                return(getAvailabilityTask.Result);
            }

            async Task <Result <EdoContracts.Accommodations.Availability, ProblemDetails> > ConvertCurrencies(EdoContracts.Accommodations.Availability availabilityDetails)
            {
                var convertedResults = new List <SlimAccommodationAvailability>(availabilityDetails.Results.Count);

                foreach (var slimAccommodationAvailability in availabilityDetails.Results)
                {
                    // Currency can differ in different results
                    var(_, isFailure, convertedAccommodationAvailability, error) = await _priceProcessor.ConvertCurrencies(agent, slimAccommodationAvailability, AvailabilityResultsExtensions.ProcessPrices,
                                                                                                                           AvailabilityResultsExtensions.GetCurrency);

                    if (isFailure)
                    {
                        return(Result.Failure <EdoContracts.Accommodations.Availability, ProblemDetails>(error));
                    }

                    convertedResults.Add(convertedAccommodationAvailability);
                }

                return(new EdoContracts.Accommodations.Availability(availabilityDetails.AvailabilityId, availabilityDetails.NumberOfNights,
                                                                    availabilityDetails.CheckInDate, availabilityDetails.CheckOutDate, convertedResults, availabilityDetails.NumberOfProcessedAccommodations));
            }

            async Task <EdoContracts.Accommodations.Availability> ApplyMarkups(EdoContracts.Accommodations.Availability response)
            {
                var markup = await _priceProcessor.ApplyMarkups(agent, response, AvailabilityResultsExtensions.ProcessPrices);

                return(markup.Data);
            }

            async Task <List <AccommodationAvailabilityResult> > Convert(EdoContracts.Accommodations.Availability details)
            {
                var supplierAccommodationIds = details.Results
                                               .Select(r => new SupplierAccommodationId(supplier, r.Accommodation.Id))
                                               .Distinct()
                                               .ToList();

                var duplicates = await _duplicatesService.GetDuplicateReports(supplierAccommodationIds);

                var timestamp = _dateTimeProvider.UtcNow().Ticks;

                return(details
                       .Results
                       .Select(accommodationAvailability =>
                {
                    var minPrice = accommodationAvailability.RoomContractSets.Min(r => r.Rate.FinalPrice.Amount);
                    var maxPrice = accommodationAvailability.RoomContractSets.Max(r => r.Rate.FinalPrice.Amount);
                    var accommodationId = new SupplierAccommodationId(supplier, accommodationAvailability.Accommodation.Id);
                    var resultId = Guid.NewGuid();
                    var duplicateReportId = duplicates.TryGetValue(accommodationId, out var reportId)
                            ? reportId
                            : string.Empty;
                    var roomContractSets = accommodationAvailability.RoomContractSets
                                           .ToRoomContractSetList()
                                           .ApplySearchFilters(searchSettings, _dateTimeProvider, request.CheckInDate);

                    return new AccommodationAvailabilityResult(resultId,
                                                               timestamp,
                                                               details.AvailabilityId,
                                                               accommodationAvailability.Accommodation,
                                                               roomContractSets,
                                                               duplicateReportId,
                                                               minPrice,
                                                               maxPrice,
                                                               request.CheckInDate,
                                                               request.CheckOutDate);
                })
                       .Where(a => a.RoomContractSets.Any())
                       .ToList());
            }

            Task SaveResult(List <AccommodationAvailabilityResult> results) => _storage.SaveResults(searchId, supplier, results);


            Task SaveState(Result <List <AccommodationAvailabilityResult>, ProblemDetails> result)
            {
                var state = result.IsSuccess
                    ? SupplierAvailabilitySearchState.Completed(searchId, result.Value.Select(r => r.DuplicateReportId).ToList(), result.Value.Count)
                    : SupplierAvailabilitySearchState.Failed(searchId, result.Error.Detail);

                if (state.TaskState == AvailabilitySearchTaskState.Completed)
                {
                    _logger.LogProviderAvailabilitySearchSuccess(
                        $"Availability search with id '{searchId}' on supplier '{supplier}' finished successfully with '{state.ResultCount}' results");
                }
                else
                {
                    _logger.LogProviderAvailabilitySearchFailure(
                        $"Availability search with id '{searchId}' on supplier '{supplier}' finished with state '{state.TaskState}', error '{state.Error}'");
                }

                return(_storage.SaveState(searchId, state, supplier));
            }
        }