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())); } }
public ReportAccommodationDuplicateRequest(SupplierAccommodationId accommodation, List <SupplierAccommodationId> duplicates) { Accommodation = accommodation; Duplicates = duplicates; }
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)); } }