/// <summary> /// adds the roomtype to the business specified, does some unavailability logic too /// </summary> /// <param name="currentRoomType">current room type</param> /// <param name="currentBusiness">current business</param> /// <param name="availabilitySearchCriteria">original search criteria</param> private void AddRoomTypeToBusiness(AvailabilityResultRoomType currentRoomType, AvailabilityResultBusiness currentBusiness, AvailabilitySearchCriteria availabilitySearchCriteria) { // add room type and business of last business / room type if (currentRoomType != null) { // filter up unavailability if (currentRoomType.RatesAndRoomsAvailable.Max(rt => rt.RoomList != null ? rt.RoomList.Count : 0) == 0 || currentRoomType.RatesAndRoomsAvailable.TrueForAll(rt => rt.UnavailabilityReason.HasValue)) { currentRoomType.UnAvailabilityReasonCode = currentRoomType.RatesAndRoomsAvailable.Min(rt => rt.UnavailabilityReason); } currentBusiness.RoomTypes.Add(currentRoomType); } }
/// <summary> /// Adds the business to the list and filters up unavailability reasons /// </summary> /// <param name="currentBusiness">current business</param> /// <param name="availableBusinesses">list of businesses for result</param> private void AddBusinessToList(AvailabilityResultBusiness currentBusiness, List<AvailabilityResultBusiness> availableBusinesses) { if (currentBusiness != null) { // filter up unavailability currentBusiness.UnavailabilityReasonCode = currentBusiness.RoomTypes.Min(rt => rt.UnAvailabilityReasonCode); // if there are any room types with availability then reset the overall business unavailability if (currentBusiness.RoomTypes.Any(r => !r.UnAvailabilityReasonCode.HasValue)) { currentBusiness.UnavailabilityReasonCode = null; } availableBusinesses.Add(currentBusiness); } }
/// <summary> /// Convert the AvailabilityResultBusiness Model to the Dto Object /// </summary> /// <param name="availabilityResultBusiness">availabilityResultBusiness to convert</param> /// <returns>AvailabilityResultBusinessDto</returns> private static AvailabilityResultBusinessDto ConvertAvailabilityResultBusinessToDto(AvailabilityResultBusiness availabilityResultBusiness) { // Convert the main object var availabilityResultBusinessDto = new AvailabilityResultBusinessDto { BusinessId = availabilityResultBusiness.BusinessId }; // Convert the sub object List<AvailabilityResultRoomTypeDto> roomTypesDtos = availabilityResultBusiness.RoomTypes.ConvertAll(ConvertAvailabilityResultRoomTypeToDto); // Finalize and return availabilityResultBusinessDto.RoomTypes = roomTypesDtos; return availabilityResultBusinessDto; }
/// <summary> /// Check Availability for supplied criteria /// </summary> /// <param name="availabilitySearchCriteria">Criteria to consider in availability check</param> /// <param name="existingBooking">booking to be modified (if already loaded)</param> /// <returns>The Availability Result based on the criteria supplied</returns> public virtual AvailabilitySearchResult CheckAvailability(AvailabilitySearchCriteria availabilitySearchCriteria, Model.Booking.Booking existingBooking = null) { Logger.LogInfo("==========CheckAvailability Called=========="); Logger.LogDebugAsXml(availabilitySearchCriteria); AvailabilitySearchResult result = null; if (availabilitySearchCriteria.ModifyBookingId.HasValue) { existingBooking = existingBooking ?? bookingManager.GetByKey(availabilitySearchCriteria.ModifyBookingId.Value); //Modify the presented criteria if this check is for a pre-existing booking result = UpdateCriteriaForExistingBooking(availabilitySearchCriteria, existingBooking); if (result != null) { return result; } } // Validate the criteria availabilitySearchCriteria.IsValid(); // Get the availability, only return available if there is no channel (help performance on pms slightly) bool onlyReturnAvailable = !availabilitySearchCriteria.ChannelId.HasValue; // set up tasks for availability / rate fetch List<RoomsAvailability> candidateRooms = null; // check if requested currency isn't one of the two for each business var criteriaSentToSproc = availabilitySearchCriteria.Clone(); Task availabilityTask = TaskProxy.StartTask( () => candidateRooms = pricingAvailabilityDao.GetAvailabilityForBusinessesBetweenDates(onlyReturnAvailable, criteriaSentToSproc)); // set up concurrent dictionary with capacity = number of businesses Dictionary<long, List<RateCache>> rateCacheDict = null; Task cacheTask = TaskProxy.StartTask(() => rateCacheDict = RateCacheManager.GetRatesByBusinessesAndDateRange (availabilitySearchCriteria.BusinessIds, availabilitySearchCriteria .StartDate.ConvertToTimeZoneLessDateTime(), availabilitySearchCriteria .EndDate.ConvertToTimeZoneLessDateTime())); Task.WaitAll(availabilityTask, cacheTask); // set the currency for the returned candidates // previously done in sproc var currencyCache = Cache.Cache.CurrencyCache.GetValue("root"); var requestedCurrency = currencyCache.Get(availabilitySearchCriteria.RequestedCurrency); string isoCode = availabilitySearchCriteria.RequestedCurrency; if (requestedCurrency != null) { isoCode = requestedCurrency.ISOCode; } foreach (var cR in candidateRooms) { cR.Currency = requestedCurrency; cR.CurrencyCode = isoCode; } // create initial list of businesses with those added that had neither currency List<AvailabilityResultBusiness> availableBusinesses = (from id in availabilitySearchCriteria.BusinessIds where !criteriaSentToSproc.BusinessIds.Contains(id) select new AvailabilityResultBusiness(UnavailabilityReasonCode.MissingCurrency, id)).ToList(); // If there is no rooms return AvailabilitySearchResult as there is no rooms to check for RoomTypes etc if (candidateRooms == null || candidateRooms.Count == 0) { // no availability or bad business, return empty result back var nullBusinessResult = GetNullBusinessAvailabilityResult(availabilitySearchCriteria); // so that if it was because of currency, we send that back nullBusinessResult.BusinessCandidates = availableBusinesses; if (nullBusinessResult.BusinessCandidates.Any(bc => bc.UnavailabilityReasonCode.HasValue)) { nullBusinessResult.UnavailabilityReasonCode = nullBusinessResult.BusinessCandidates.First(bc => bc.UnavailabilityReasonCode.HasValue).UnavailabilityReasonCode; } return nullBusinessResult; } // assign cache and deal with 0 prices / minloss based on cache results UpdateAvailabilityWithRateCache(availabilitySearchCriteria, candidateRooms, rateCacheDict); // set prepay based on rates set from above UpdateAvailabilityWithPrepay(candidateRooms, availabilitySearchCriteria); // If modify booking for an OTA booking then update all the rates with the current booking rate as OTA booking pricing cannot be changed if (availabilitySearchCriteria.ModifyBookingId.HasValue && existingBooking.Order.IsOTA) { // Set all fields on the available room object foreach (var room in candidateRooms) { room.TotalRate = existingBooking.Cost.Value; SetRoomTypeName(room); } } else { candidateRooms.ForEach(SetRoomTypeName); } // Create the object to be returned result = new AvailabilitySearchResult { StartDate = availabilitySearchCriteria.StartDate, EndDate = availabilitySearchCriteria.EndDate, NoOfAdults = availabilitySearchCriteria.NumberOfAdults, NoOfChildren = availabilitySearchCriteria.NumberOfChildren }; // sort the results by business AvailabilityResultBusiness currentBusiness = null; AvailabilityResultRoomType currentRoomType = null; foreach (RoomsAvailability candidate in candidateRooms) { if (currentBusiness == null || candidate.BusinessId != currentBusiness.BusinessId) { // Currently needs update to get all the businesses in list // We also need to check the criteria is valid for the correct time zone of the businesses. All businesses are assumed in the same time zone var business = Cache.Cache.Business.TryGetValue(candidate.BusinessId); if (business == null) { continue; } // for last of previous business AddRoomTypeToBusiness(currentRoomType, currentBusiness, availabilitySearchCriteria); currentRoomType = null; // add old business to list AddBusinessToList(currentBusiness, availableBusinesses); // set up new business var newBusiness = new AvailabilityResultBusiness { BusinessId = candidate.BusinessId, ShortName = business.ShortName, RoomTypes = new List<AvailabilityResultRoomType>(), Is3DSecureAllowed = business.MerchantDetails.Is3DSecureAllowed ?? true, IsAmexAllowed = business.MerchantDetails.IsAmexAllowed ?? true, IsPaypalAllowed = business.MerchantDetails.IsPaypalAllowed ?? false }; currentBusiness = newBusiness; } // add this roomtype candidate to the business if (currentRoomType == null || candidate.RoomTypeId != currentRoomType.RoomTypeId) { // first add the old one if it is present AddRoomTypeToBusiness(currentRoomType, currentBusiness, availabilitySearchCriteria); // set up new room type AvailabilityResultRoomType newRoomType = new AvailabilityResultRoomType { RoomTypeId = candidate.RoomTypeId, BusinessId = candidate.BusinessId, RoomTypeName = candidate.RoomTypeName, RatesAndRoomsAvailable = new List<RoomsAvailability>(), UnAvailabilityReasonCode = null }; currentRoomType = newRoomType; } currentRoomType.RatesAndRoomsAvailable.Add(candidate); } AddRoomTypeToBusiness(currentRoomType, currentBusiness, availabilitySearchCriteria); AddBusinessToList(currentBusiness, availableBusinesses); if (!availableBusinesses.Any()) { // bad business list, return empty result back return GetNullBusinessAvailabilityResult(availabilitySearchCriteria); } result.BusinessCandidates = availableBusinesses; CorrectWasPriceForResults(candidateRooms); Logger.LogInfo("==========CheckAvailability Returns=========="); Logger.LogDebugAsXml(result); return result; }
/// <summary> /// Convert the AvailabilityResultBusiness Model to the Dto Object /// </summary> /// <param name="availabilityResultBusiness">availabilityResultBusiness to convert</param> /// <returns>AvailabilityResultBusinessDto</returns> private static OnlineAvailabilityResultBusinessDto ConvertAvailabilityResultBusinessToOnlineDto(AvailabilityResultBusiness availabilityResultBusiness) { // Convert the main object var availabilityResultBusinessDto = new OnlineAvailabilityResultBusinessDto { BusinessId = availabilityResultBusiness.BusinessId, ShortName = availabilityResultBusiness.ShortName, Is3DSecureAllowed = availabilityResultBusiness.Is3DSecureAllowed, IsAmexAllowed = availabilityResultBusiness.IsAmexAllowed, IsPaypalAllowed = availabilityResultBusiness.IsPaypalAllowed }; // Convert the sub object var roomsAvailable = new List<RoomsAvailabilityDto>(); availabilityResultBusiness.RoomTypes.ForEach(rt => roomsAvailable.AddRange(Mapper.Map<List<RoomsAvailabilityDto>>(rt.RatesAndRoomsAvailable))); // Get all the reason codes present var reasonCodes = new List<UnavailabilityReasonCodeDto>(); if (availabilityResultBusiness.UnavailabilityReasonCode != null) { reasonCodes.Add((UnavailabilityReasonCodeDto)availabilityResultBusiness.UnavailabilityReasonCode); } // Finalize and return availabilityResultBusinessDto.RoomTypes = roomsAvailable; availabilityResultBusinessDto.NoAvailabilityReasons = reasonCodes; return availabilityResultBusinessDto; }