示例#1
0
        /// <summary>
        /// Create an order
        /// </summary>
        /// <param name="orderRequest">Order Request Dto</param>
        /// <returns>OrderResponseDto</returns>
        ///<remarks>
        /// Create orders steps :
        ///   -We search availability to find a free rooms
        ///   -We assign these rooms to each bookings
        ///     -if PUSH channel and no availability we assign rooms of the same type anyway
        ///     -if no PUSH channel and no availability we return null meaning no availability
        ///   -We return the order reference
        /// </remarks>
        public OrderResponseDto CreateOrder(OrderRequestDto orderRequest)
        {
            OrderResponseDto responseDto = null;

            // Log request
            Log.LogInfo("CreateOrder request: {0}", null, orderRequest);
            Log.LogInfoAsXml(orderRequest);

            #region Precondition

            var business = businessManager.GetLimitedBusinessByShortname(orderRequest.BusinessShortName);

            if (business == null)
            {
                return null;
            }

            var channel = distributionManager.GetChannelByShortName(orderRequest.ChannelShortName);

            if (channel == null)
            {
                return null;
            }

            #endregion

            orderRequest.ChannelId = channel.Id;

            var roomIdsReserved = new List<int>();
            var searchResults = new Dictionary<BookingRequestDto, AvailabilitySearchResult>();
            var rooms = new Dictionary<BookingRequestDto, List<Room>>();

            bool isAvailable = SearchAvailability(orderRequest, rooms, business, searchResults);

            if (isAvailable == true || orderRequest.AllowOverbooking == true)
            {
                bool isOverBooking = false;
                bool isOverLoaded = false;
                string reasonForOverbooking = null;

                var bookings = AllocateBookings(orderRequest, searchResults, roomIdsReserved, rooms, out isOverBooking, out isOverLoaded, out reasonForOverbooking);

                if ((isOverBooking == false || orderRequest.AllowOverbooking == true) && isOverLoaded == false)
                {
                    if (isOverBooking)
                    {
                        log.LogWarn("There is an overbooking on the order {0} for the business with shortname {1}", orderRequest.ChannelReference, orderRequest.BusinessShortName);
                    }

                    //Abs does not manage the currency well so we default to the business working currency
                    // Also set up order, then call create order first
                    var order = new Order
                                    {
                                        CustomerCurrencyCode = string.IsNullOrWhiteSpace(orderRequest.CurrencyCode) ? business.WorkingCurrencyCode : orderRequest.CurrencyCode,
                                        ChannelId = channel.Id,
                                        Channel = channel,
                                        IntegrationType = channel.IntegrationType,
                                        OrderSourceCode = SourceType.Online.GetCode(),
                                        ChannelReference = orderRequest.ChannelReference,
                                        LeadGuest = Mapper.Map<Guest>(orderRequest.Guest),
                                        Bookings = bookings,
                                        IsIssue = !string.IsNullOrEmpty(reasonForOverbooking),
                                        ReasonForIssue = reasonForOverbooking
                                    };

                    order.LeadGuest.BusinessId = business.Id;

                    var success = orderManager.CreateOrder(business.Id, order);

                    if (success && order.Id.HasValue)
                    {
                        // Return the updated Order with Bookings (make sure to get the full object from database since the OrderReference is only generated in SQL code)
                        responseDto =
                            Mapper.Map<Order, OrderResponseDto>(orderManager.GetOrderWithBookingsByKey(order.Id.Value));
                    }
                }
            }

            Log.LogInfo("CreateOrder response: {0}", null, responseDto);
            Log.LogInfoAsXml(responseDto);

            return responseDto;
        }
示例#2
0
        private AvailabilitySearchResult FindRoomAndRatePlan(OrderRequestDto order, BookingRequestDto bookingRequest)
        {
            Model.Business.Business business =
                businessManager.GetLimitedBusinessByShortname(order.BusinessShortName);

            if (business == null)
            {
                return null;
            }

            var currency = business.WorkingCurrencyCode;

            AvailabilitySearchCriteria availabilitySearchCriteria = new AvailabilitySearchCriteria
            {
                BusinessIds = new List<long>
                            {
                                business.Id
                            },
                StartDate =
                    CalendarDate.ConvertToCalendarDate(
                        bookingRequest.StartDate),
                EndDate =
                    CalendarDate.ConvertToCalendarDate(
                        bookingRequest.EndDate),
                NumberOfAdults = bookingRequest.NumberOfAdults,
                NumberOfChildren = bookingRequest.NumberOfChildren,
                RatePlanId = bookingRequest.RatePlanId,
                RoomTypeId = bookingRequest.RoomTypeId,
                RequestedCurrency = currency,
                ChannelId = order.ChannelId
            };

            // Get the results
            AvailabilitySearchResult result = availabilityManager.CheckAvailability(availabilitySearchCriteria);

            return result;
        }
示例#3
0
        /// <summary>
        /// Allocate the different rooms asked
        /// </summary>
        /// <param name="orderRequest">OrderRequestDto</param>
        /// <param name="searchResults">Availability search result Dictionnary indexed by request object</param>
        /// <param name="roomIdsReserved">List of reserved room ids</param>
        /// <param name="rooms">List of all the rooms for the room type asked</param>
        /// <param name="isOverBooking">Yes or not this allocation will result as an overbooking</param>
        /// <param name="isOverLoaded">Yes or not this allocation has been full filled completely</param>
        /// <param name="reasonForOverbooking">Indicates the reason for over booking</param>
        /// <remarks>
        /// Regarding isOverLoaded, a room can be overloaded in the case of Laterooms because
        /// they do not use our multi rooms search, as a consequence they construct a false
        /// inventory cache and can think that the hotel has more rooms that it has in reality.
        /// 
        /// For push channel they already know perfectly the inventory of the hotel, so they would not
        /// try to do a multiple rooms booking with more rooms that the hotel has for a particulary
        /// room type
        /// </remarks>
        /// <returns>Return the list of booking allocated</returns>
        private static List<Booking> AllocateBookings(
            OrderRequestDto orderRequest, 
            Dictionary<BookingRequestDto, AvailabilitySearchResult> searchResults, 
            List<int> roomIdsReserved,
            Dictionary<BookingRequestDto, List<Room>> rooms, out bool isOverBooking, out bool isOverLoaded, out string reasonForOverbooking)
        {
            isOverBooking = false;
            isOverLoaded = false;
            StringBuilder unavailabilityReasons = new  StringBuilder();

            var bookings = new List<Booking>();

            foreach (var searchResult in searchResults)
            {
                // Convert to Model
                var internalBooking = DataTransferObjectsConverter.ConvertBookingOnlineDtoToBooking(orderRequest,
                                                                                                    searchResult.Key);
                if (searchResult.Value.FirstRoomIdsAvailable != null)
                {
                    foreach (int roomId in searchResult.Value.FirstRoomIdsAvailable)
                    {
                        if (!roomIdsReserved.Contains(roomId))
                        {
                            AllocateBookingToRoom(internalBooking,
                                                  searchResult.Value.FirstRoomTypeIdAvailable,
                                                  searchResult.Value.FirstRoomRatePlanIdAvailable, roomId, bookings);
                            roomIdsReserved.Add(roomId);

                            // Reason for Unavailability
                            if (searchResult.Value.UnavailabilityReasonCode.HasValue)
                            {
                                unavailabilityReasons.Append(
                                    searchResult.Value.UnavailabilityReasonCode.Value.ToString());
                            }
                            else if (searchResult.Value.BusinessCandidates[0].UnavailabilityReasonCode.HasValue)
                            {
                                unavailabilityReasons.Append(
                                    searchResult.Value.BusinessCandidates[0].UnavailabilityReasonCode.Value.ToString());
                            }
                            break;
                        }
                    }
                }

                //Force overbooking if all rooms reserved
                if (!bookings.Contains(internalBooking))
                {
                    foreach (var room in rooms[searchResult.Key])
                    {
                        if (!roomIdsReserved.Contains(room.Id))
                        {
                            AllocateBookingToRoom(internalBooking,
                                                  room.RoomTypeId,
                                                  internalBooking.RatePlanId.Value, room.Id, bookings);

                            roomIdsReserved.Add(room.Id);
                            isOverBooking = true;

                            // Reason for Unavailability
                            if (searchResult.Value.UnavailabilityReasonCode.HasValue)
                            {
                                unavailabilityReasons.Append(
                                    searchResult.Value.UnavailabilityReasonCode.Value.ToString());
                            }
                            else if (searchResult.Value.BusinessCandidates[0].UnavailabilityReasonCode.HasValue)
                            {
                                unavailabilityReasons.Append(
                                    searchResult.Value.BusinessCandidates[0].UnavailabilityReasonCode.Value.ToString());
                            }
                            break;
                        }
                    }
                }
            }

            //if the number of rooms allocated is less than
            //the number of rooms asked we declare the order over loaded
            isOverLoaded = (searchResults.Count() > bookings.Count);

            reasonForOverbooking = unavailabilityReasons.Length > 0 ? OVERBOOKING_PREFIX + unavailabilityReasons.ToString() : null;

            return bookings;
        }
示例#4
0
        private bool SearchAvailability(
            OrderRequestDto orderRequest, 
            Dictionary<BookingRequestDto, List<Room>> rooms, 
            Model.Business.Business business,
            Dictionary<BookingRequestDto, 
            AvailabilitySearchResult> searchResults)
        {
            bool isAvailable = true;

            foreach (var booking in orderRequest.Bookings)
            {
                var roomList = roomManager.GetRoomsByBusinessRoomType(booking.RoomTypeId, business.Id);

                if (roomList.Count() == 0)
                {
                    throw new ValidationException(ErrorFactory.CreateAndLogError(Errors.SRVEX30140,
                                                                                 "BookingService.SearchAvailability",
                                                                                 descriptionParameters:
                                                                                     new object[]
                                                                                         {
                                                                                             booking.RoomTypeId,
                                                                                             business.Id
                                                                                         },
                                                                                 arguments:
                                                                                     new object[]
                                                                                         {
                                                                                             booking.RoomTypeId,
                                                                                             business.Id
                                                                                         }));
                }

                rooms.Add(booking, roomList);

                var searchResult = FindRoomAndRatePlan(orderRequest, booking);

                searchResults.Add(booking, searchResult);

                if (searchResult == null || searchResult.IsOneRoomWithRatePlanMatched == false)
                {
                    isAvailable = false;

                    if (searchResult != null && searchResult.BusinessCandidates != null)
                    {
                        foreach (var businessCandidate in searchResult.BusinessCandidates)
                        {
                            if (businessCandidate.UnavailabilityReasonCode.HasValue)
                            {
                               
                                Log.LogInfo("No Availability reason: {0}", null,
                                            businessCandidate.UnavailabilityReasonCode.Value.ToString());
                                Log.LogInfoAsXml(businessCandidate);
                            }
                        }
                    }
                }
            }
            return isAvailable;
        }
        /// <summary>
        ///  Convert Booking Dto to Booking business domain
        /// </summary>
        /// <param name="order">OrderRequestDto</param>
        /// <param name="booking">BookingRequestDto</param>
        /// <returns>Booking</returns>
        public static Booking ConvertBookingOnlineDtoToBooking(OrderRequestDto order, BookingRequestDto booking)
        {
            var businessManager = new BusinessManager();
            Model.Business.Business business = businessManager.GetLimitedBusinessByShortname(order.BusinessShortName);

            if (business != null)
            {
                var book = new Booking
                {
                    BusinessId = business.Id,
                    BookingReferenceNumber = order.BookingReferenceNumber,
                    StartDate = booking.StartDate,
                    EndDate = booking.EndDate,
                    NumberOfAdults = booking.NumberOfAdults,
                    NumberOfChildren = booking.NumberOfChildren,
                    Cost = booking.Cost,
                    RoomTypeId = booking.RoomTypeId,
                    RoomId = booking.RoomId,
                    RatePlanId = booking.RatePlanId,
                    CheckinStatus = ConvertCodeAndNameToEnumEntity(booking.CheckinStatusCode),
                    BookingScenarioType = (BookingScenarioTypeEnum)order.BookingScenarioType,
                    Notes = booking.Notes,
                    BookingStatus = ConvertCodeAndNameToEnumEntity(booking.BookingStatusCode),
                    CreatedByUserId = order.CreatedByUserId,
                    CreatedDateTime = order.CreatedDateTime,
                    RateType = ConvertCodeAndNameToEnumEntity(RateType.BEST_AVAILABLE_RATE),
                    ChannelCommissionOverride = booking.ChannelCommissionOverride,
                    Extras = booking.Extras == null ? null : booking.Extras.ConvertAll(MapToOnlineBookingExtra)
                };
                order.Guest.BusinessId = business.Id;
                return book;
            }

            return null;
        }