private Image Create(int serviceSupplierId, Models.Requests.RoomImage image) => new Image
 {
     ReferenceId          = image.RoomId,
     ImageType            = ImageTypes.RoomImage,
     OriginalImageDetails = new OriginalImageDetails
     {
         OriginalName        = image.UploadedFile.FileName,
         OriginalContentType = image.UploadedFile.ContentType
     },
     ServiceSupplierId = serviceSupplierId,
     Created           = _dateTimeProvider.UtcNow(),
     Description       = JsonDocumentUtilities.CreateJDocument(new MultiLanguage <string> {
         Ar = string.Empty, En = string.Empty, Ru = string.Empty
     })
 };
        private async Task <Result> ArrangeImages(List <Image> dbImages, List <Models.Requests.SlimImage> images)
        {
            for (var i = 0; i < images.Count; i++)
            {
                var dbImage = dbImages.SingleOrDefault(image => image.Id == images[i].Id);
                if (dbImage != null)
                {
                    dbImage.Position    = i;
                    dbImage.Description = JsonDocumentUtilities.CreateJDocument(images[i].Description);

                    _dbContext.Images.Update(dbImage);
                }
            }
            await _dbContext.SaveChangesAsync();

            return(Result.Success());
        }
        public async Task <Result <Common.Models.Bookings.BookingOrder> > Book(EdoContracts.Accommodations.BookingRequest bookingRequest, EdoContracts.Accommodations.AvailabilityRequest availabilityRequest, string languageCode)
        {
            return(await GetRequiredHash()
                   .BindWithTransaction(_dbContext, requiredHash => GetAvailableRates(requiredHash)
                                        .Map(CreateBookingEntry)
                                        .Map(AddBookingEntry)
                                        .Bind(AddRoomOccupancy)));


            async Task <Result <string> > GetRequiredHash()
            {
                var hash = await _availabilityDataStorage.GetHash(bookingRequest.AvailabilityId, bookingRequest.RoomContractSetId);

                return(string.IsNullOrEmpty(hash)
                    ? Result.Failure <string>("Failed to retrieve the required hash")
                    : Result.Success(hash));
            }

            async Task <Result <AvailableRates> > GetAvailableRates(string requiredHash)
            {
                var error        = "Available rates not found";
                var availability = await _availabilityService.Get(availabilityRequest, languageCode);

                if (!availability.AvailableRates.Any())
                {
                    Result.Failure <Common.Models.Availabilities.Availability>(error);
                }

                foreach (var availableRates in availability.AvailableRates)
                {
                    var requiredRates = availableRates.Value.SingleOrDefault(ar => ar.Hash.Equals(requiredHash));
                    if (requiredRates != null)
                    {
                        return(Result.Success(requiredRates));
                    }
                }

                return(Result.Failure <AvailableRates>(error));
            }

            (Common.Models.Bookings.BookingOrder, AvailableRates) CreateBookingEntry(AvailableRates availableRates)
            {
                var accommodation = availableRates.Rates.First().Room.Accommodation;
                var utcNow        = _dateTimeProvider.UtcNow();

                return(new Common.Models.Bookings.BookingOrder
                {
                    Status = BookingStatuses.WaitingForConfirmation,
                    ReferenceCode = bookingRequest.ReferenceCode,
                    CheckInDate = availabilityRequest.CheckInDate,
                    CheckOutDate = availabilityRequest.CheckOutDate,
                    Created = utcNow,
                    Modified = utcNow,
                    BookingRequest = JsonDocumentUtilities.CreateJDocument(bookingRequest),
                    AvailabilityRequest = JsonDocumentUtilities.CreateJDocument(availabilityRequest),
                    AvailableRates = JsonDocumentUtilities.CreateJDocument(availableRates),
                    LanguageCode = languageCode,
                    ServiceSupplierId = accommodation.ServiceSupplierId,
                    AccommodationId = accommodation.Id
                }, availableRates);
            }

            async Task <(Common.Models.Bookings.BookingOrder bookingOrder, AvailableRates availableRates)> AddBookingEntry((Common.Models.Bookings.BookingOrder bookingOrder, AvailableRates availableRates) bookingOrderAndAvailableRates)
            {
                var entry = _dbContext.BookingOrders.Add(bookingOrderAndAvailableRates.bookingOrder);
                await _dbContext.SaveChangesAsync();

                _dbContext.DetachEntry(entry.Entity);

                return(entry.Entity, bookingOrderAndAvailableRates.availableRates);
            }

            async Task <Result <Common.Models.Bookings.BookingOrder> > AddRoomOccupancy((Common.Models.Bookings.BookingOrder bookingOrder, AvailableRates availableRates) bookingOrderAndAvailableRates)
            {
                var utcNow = _dateTimeProvider.UtcNow();

                foreach (var roomId in bookingOrderAndAvailableRates.availableRates.Rates.Select(rd => rd.Room.Id))
                {
                    _dbContext.RoomOccupancies.Add(new RoomOccupancy
                    {
                        RoomId         = roomId,
                        Created        = utcNow,
                        FromDate       = availabilityRequest.CheckInDate,
                        ToDate         = availabilityRequest.CheckOutDate,
                        BookingOrderId = bookingOrderAndAvailableRates.bookingOrder.Id
                    });
                }

                await _dbContext.SaveChangesAsync();

                return(Result.Success(bookingOrderAndAvailableRates.bookingOrder));
            }
        }