Esempio n. 1
0
        public async Task <Result <AccommodationBookingInfo> > Execute(AccommodationBookingRequest request, Func <Task <Result <AccommodationBookingInfo> > > bookingFunction, string languageCode)
        {
            return(await _functionExecutor.Execute(executingFunction : async() => await bookingFunction().Tap(SaveEvaluationTokenMapping),
                                                   getResultFunction : () => GetBookingByEvaluationToken(request.EvaluationToken, languageCode),
                                                   operationKey : request.EvaluationToken,
                                                   maximumDuration : MaximumBookingDuration));


            Task SaveEvaluationTokenMapping(AccommodationBookingInfo bookingInfo)
            {
                var key = GetEvaluationTokenKey(request.EvaluationToken);

                return(_flow.SetAsync(key, bookingInfo.BookingDetails.ReferenceCode, EvaluationTokenMappingLifeTime));
            }

            async Task <Result <AccommodationBookingInfo> > GetBookingByEvaluationToken(string evaluationToken, string languageCode)
            {
                var key           = GetEvaluationTokenKey(request.EvaluationToken);
                var referenceCode = await _flow.GetAsync <string>(key, EvaluationTokenMappingLifeTime);

                if (referenceCode is null)
                {
                    return(Result.Failure <AccommodationBookingInfo>("Could not find booking reference code"));
                }

                return(await _bookingInfoService.GetAccommodationBookingInfo(referenceCode, languageCode));
            }

            string GetEvaluationTokenKey(string evaluationToken)
            => _flow.BuildKey(nameof(IdempotentBookingExecutor), evaluationToken);
        }
Esempio n. 2
0
        public async Task <Result <Booking> > Register(AccommodationBookingRequest request, AgentContext agent, string languageCode)
        {
            return(await _validationService.Validate(request.ClientReferenceCode, agent)
                   .Bind(GetCachedAvailability)
                   .Bind(RegisterBooking));


            async Task <Result <BookingAvailabilityInfo> > GetCachedAvailability()
            => await _bookingEvaluationStorage.Get(request.SearchId,
                                                   request.AccommodationId,
                                                   request.RoomContractSetId);


            async Task <Result <Booking> > RegisterBooking(BookingAvailabilityInfo availabilityInfo)
            {
                var booking = await _bookingRegistrationService.Register(bookingRequest : request.ToEdoModel(),
                                                                         availabilityInfo : availabilityInfo,
                                                                         paymentMethod : PaymentTypes.VirtualAccount,
                                                                         agentContext : agent,
                                                                         languageCode : languageCode);

                return(booking.IsSuccess
                    ? booking.Value.FromEdoModels()
                    : Result.Failure <Booking>(booking.Error));
            }
        }
        public Task <Result <AccommodationBookingInfo> > BookByAccount(AccommodationBookingRequest bookingRequest,
                                                                       AgentContext agentContext, string languageCode, string clientIp)
        {
            Baggage.AddSearchId(bookingRequest.SearchId);
            _logger.LogBookingByAccountStarted(bookingRequest.HtId);

            return(GetCachedAvailability(bookingRequest)
                   .Ensure(IsPaymentTypeAllowed, "Payment type is not allowed")
                   .Bind(RegisterBooking)
                   .Check(GenerateInvoice)
                   .CheckIf(IsDeadlinePassed, ChargeMoney)
                   .Bind(SendSupplierRequest)
                   .Bind(GetAccommodationBookingInfo)
                   .Finally(WriteLog));


            bool IsDeadlinePassed(Data.Bookings.Booking booking)
            => booking.GetPayDueDate() <= _dateTimeProvider.UtcToday();


            async Task <Result <BookingAvailabilityInfo> > GetCachedAvailability(AccommodationBookingRequest bookingRequest)
            => await _bookingEvaluationStorage.Get(bookingRequest.SearchId,
                                                   bookingRequest.HtId,
                                                   bookingRequest.RoomContractSetId);


            bool IsPaymentTypeAllowed(BookingAvailabilityInfo availabilityInfo)
            => availabilityInfo.AvailablePaymentTypes.Contains(PaymentTypes.VirtualAccount);


            Task <Result <Data.Bookings.Booking> > RegisterBooking(BookingAvailabilityInfo bookingAvailability)
            => _registrationService.Register(bookingRequest, bookingAvailability, PaymentTypes.VirtualAccount, agentContext, languageCode);


            async Task <Result> ChargeMoney(Data.Bookings.Booking booking)
            => await _accountPaymentService.Charge(booking, agentContext.ToApiCaller());


            Task <Result> GenerateInvoice(Data.Bookings.Booking booking)
            => _documentsService.GenerateInvoice(booking);


            async Task <Result <Booking> > SendSupplierRequest(Data.Bookings.Booking booking)
            {
                var refreshedBooking = await _recordManager.Get(booking.ReferenceCode);

                return(await _requestExecutor.Execute(refreshedBooking.Value, agentContext, languageCode));
            }

            Task <Result <AccommodationBookingInfo> > GetAccommodationBookingInfo(EdoContracts.Accommodations.Booking details)
            => _bookingInfoService.GetAccommodationBookingInfo(details.ReferenceCode, languageCode);


            Result <AccommodationBookingInfo> WriteLog(Result <AccommodationBookingInfo> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingByAccountSuccess(result.Value.BookingDetails.ReferenceCode),
                                            () => _logger.LogBookingByAccountFailure(bookingRequest.HtId, result.Error));
        }
Esempio n. 4
0
        public Task <Result <AccommodationBookingInfo> > Book(AccommodationBookingRequest bookingRequest,
                                                              AgentContext agentContext, string languageCode, string clientIp)
        {
            Baggage.AddSearchId(bookingRequest.SearchId);
            _logger.LogBookingByOfflinePaymentStarted(bookingRequest.HtId);

            return(GetCachedAvailability(bookingRequest)
                   .Ensure(IsPaymentTypeAllowed, "Payment type is not allowed")
                   .Ensure(IsDeadlineNotPassed, "Deadline already passed, can not book")
                   .Bind(RegisterBooking)
                   .Check(GenerateInvoice)
                   .Bind(SendSupplierRequest)
                   .Bind(GetAccommodationBookingInfo)
                   .Finally(WriteLog));


            bool IsDeadlineNotPassed(BookingAvailabilityInfo bookingAvailability)
            {
                var deadlineDate = bookingAvailability.RoomContractSet.Deadline.Date;
                var dueDate      = deadlineDate == null || deadlineDate == DateTime.MinValue ? bookingAvailability.CheckInDate : deadlineDate.Value;

                return(_dateTimeProvider.UtcToday() < dueDate - BookingPaymentTypesHelper.OfflinePaymentAdditionalDays);
            }

            async Task <Result <BookingAvailabilityInfo> > GetCachedAvailability(AccommodationBookingRequest bookingRequest)
            => await _bookingEvaluationStorage.Get(bookingRequest.SearchId,
                                                   bookingRequest.HtId,
                                                   bookingRequest.RoomContractSetId);


            bool IsPaymentTypeAllowed(BookingAvailabilityInfo availabilityInfo)
            => availabilityInfo.AvailablePaymentTypes.Contains(PaymentTypes.Offline);


            Task <Result <Data.Bookings.Booking> > RegisterBooking(BookingAvailabilityInfo bookingAvailability)
            => _registrationService.Register(bookingRequest, bookingAvailability, PaymentTypes.Offline, agentContext, languageCode);


            Task <Result> GenerateInvoice(Data.Bookings.Booking booking)
            => _documentsService.GenerateInvoice(booking);


            async Task <Result <Booking> > SendSupplierRequest(Data.Bookings.Booking booking)
            {
                return(await _requestExecutor.Execute(booking,
                                                      agentContext,
                                                      languageCode));
            }

            Task <Result <AccommodationBookingInfo> > GetAccommodationBookingInfo(EdoContracts.Accommodations.Booking details)
            => _bookingInfoService.GetAccommodationBookingInfo(details.ReferenceCode, languageCode);


            Result <AccommodationBookingInfo> WriteLog(Result <AccommodationBookingInfo> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingByAccountSuccess(result.Value.BookingDetails.ReferenceCode),
                                            () => _logger.LogBookingByOfflinePaymentFailure(bookingRequest.HtId, result.Error));
        }
Esempio n. 5
0
        public async Task <ActionResult <Booking> > Register([FromBody] AccommodationBookingRequest request)
        {
            var agent = await _agentContextService.GetAgent();

            var(isSuccess, _, booking, error) = await _bookingCreationService.Register(request, agent, "en");

            return(isSuccess
                ? Ok(booking)
                : BadRequest(ProblemDetailsBuilder.Build(error)));
        }
        public async Task <IActionResult> RegisterBooking([FromBody] AccommodationBookingRequest request)
        {
            var(_, isFailure, refCode, error) = await _bookingRegistrationService.Register(request, await _agentContextService.GetAgent(), LanguageCode);

            if (isFailure)
            {
                return(BadRequest(error));
            }

            return(Ok(refCode));
        }
Esempio n. 7
0
        public async Task <IActionResult> RegisterBooking([FromBody] AccommodationBookingRequest request)
        {
            var(_, isFailure, refCode, error) = await _bankCreditCardBookingFlow.Register(request, await _agentContextService.GetAgent(), LanguageCode);

            if (isFailure)
            {
                return(BadRequest(ProblemDetailsBuilder.Build(error)));
            }

            return(Ok(refCode));
        }
Esempio n. 8
0
        public Task Set(string referenceCode, AccommodationBookingRequest request, BookingAvailabilityInfo availabilityInfo)
        {
            var bookingRequest = new BookingRequest
            {
                ReferenceCode    = referenceCode,
                RequestData      = JsonConvert.SerializeObject(request),
                AvailabilityData = JsonConvert.SerializeObject(availabilityInfo),
            };

            _edoContext.BookingRequests.Add(bookingRequest);
            return(_edoContext.SaveChangesAsync());
        }
Esempio n. 9
0
        public async Task <IActionResult> Book([FromBody] AccommodationBookingRequest request)
        {
            var agentContext = await _agentContextService.GetAgent();

            var(_, isFailure, bookingInfo, error) = await _idempotentBookingExecutor.Execute(request : request,
                                                                                             bookingFunction : () => _financialAccountBookingFlow.BookByAccount(request, agentContext, LanguageCode, ClientIp),
                                                                                             languageCode : LanguageCode);

            if (isFailure)
            {
                return(BadRequest(ProblemDetailsBuilder.Build(error)));
            }

            return(Ok(bookingInfo));
        }
 public static Edo.Api.Models.Bookings.AccommodationBookingRequest ToEdoModel(this AccommodationBookingRequest request)
 {
     return(new Edo.Api.Models.Bookings.AccommodationBookingRequest(itineraryNumber: string.Empty,
                                                                    clientReferenceCode: request.ClientReferenceCode,
                                                                    roomDetails: request.RoomDetails
                                                                    .Select(r => r.ToEdoModel())
                                                                    .ToList(),
                                                                    features: new List <Api.Models.Accommodations.AccommodationFeature>(),
                                                                    searchId: request.SearchId,
                                                                    htId: request.AccommodationId,
                                                                    roomContractSetId: request.RoomContractSetId,
                                                                    mainPassengerName: GetMainPassengerName(request.RoomDetails),
                                                                    evaluationToken: null,
                                                                    rejectIfUnavailable: true));
 }
Esempio n. 11
0
        public async Task <Result <string, ProblemDetails> > Register(AccommodationBookingRequest bookingRequest, AgentContext agentContext, string languageCode)
        {
            string availabilityId = default;
            var    settings       = await _accommodationBookingSettingsService.Get(agentContext);

            return(await GetCachedAvailability(bookingRequest, agentContext)
                   .Ensure(AreAprSettingsSuitable, ProblemDetailsBuilder.Build("You can't book the restricted contract without explicit approval from a Happytravel.com officer."))
                   .Ensure(AreDeadlineSettingsSuitable, ProblemDetailsBuilder.Build("You can't book the contract within deadline without explicit approval from a Happytravel.com officer."))
                   .Tap(FillAvailabilityId)
                   .Map(ExtractBookingAvailabilityInfo)
                   .Map(Register)
                   .Finally(WriteLog));


            bool AreAprSettingsSuitable(
                (Suppliers, DataWithMarkup <RoomContractSetAvailability>) bookingData)
            => BookingRegistrationService.AreAprSettingsSuitable(bookingRequest, bookingData, settings);


            bool AreDeadlineSettingsSuitable(
                (Suppliers, DataWithMarkup <RoomContractSetAvailability>) bookingData)
            => this.AreDeadlineSettingsSuitable(bookingRequest, bookingData, settings);


            void FillAvailabilityId((Suppliers, DataWithMarkup <RoomContractSetAvailability> Result) responseWithMarkup)
            => availabilityId = responseWithMarkup.Result.Data.AvailabilityId;


            async Task <string> Register(BookingAvailabilityInfo bookingAvailability)
            {
                var bookingRequestWithAvailabilityId = new AccommodationBookingRequest(bookingRequest, availabilityId);

                return(await _bookingRecordsManager.Register(bookingRequestWithAvailabilityId, bookingAvailability, agentContext, languageCode));
            }

            Result <string, ProblemDetails> WriteLog(Result <string, ProblemDetails> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingRegistrationSuccess($"Successfully registered a booking with reference code: '{result.Value}'"),
                                            () => _logger.LogBookingRegistrationFailure($"Failed to register a booking. AvailabilityId: '{availabilityId}'. " +
                                                                                        $"Itinerary number: {bookingRequest.ItineraryNumber}. Passenger name: {bookingRequest.MainPassengerName}. Error: {result.Error.Detail}"));
        }
        public async Task <Result <string> > Register(AccommodationBookingRequest bookingRequest, AgentContext agentContext, string languageCode)
        {
            Baggage.AddSearchId(bookingRequest.SearchId);
            _logger.LogCreditCardBookingFlowStarted(bookingRequest.HtId);

            var(_, isFailure, booking, error) = await GetCachedAvailability(bookingRequest)
                                                .Ensure(IsPaymentTypeAllowed, "Payment type is not allowed")
                                                .Bind(Register)
                                                .Check(SendEmailToPropertyOwner)
                                                .Finally(WriteLog);

            if (isFailure)
            {
                return(Result.Failure <string>(error));
            }

            return(booking.ReferenceCode);

            async Task <Result <BookingAvailabilityInfo> > GetCachedAvailability(AccommodationBookingRequest bookingRequest)
            => await _evaluationStorage.Get(bookingRequest.SearchId, bookingRequest.HtId, bookingRequest.RoomContractSetId);


            bool IsPaymentTypeAllowed(BookingAvailabilityInfo availabilityInfo)
            => availabilityInfo.AvailablePaymentTypes.Contains(PaymentTypes.CreditCard);


            Task <Result <Booking> > Register(BookingAvailabilityInfo bookingAvailability)
            => _registrationService.Register(bookingRequest, bookingAvailability, PaymentTypes.CreditCard, agentContext, languageCode);


            async Task <Result> SendEmailToPropertyOwner(Booking booking)
            => await _bookingConfirmationService.SendConfirmationEmail(booking);


            Result <Booking> WriteLog(Result <Booking> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingRegistrationSuccess(result.Value.ReferenceCode),
                                            () => _logger.LogBookingRegistrationFailure(bookingRequest.HtId, bookingRequest.ItineraryNumber, bookingRequest.MainPassengerName, result.Error));
        }
Esempio n. 13
0
        public async Task <Result <AccommodationBookingInfo, ProblemDetails> > BookByAccount(AccommodationBookingRequest bookingRequest,
                                                                                             AgentContext agentContext, string languageCode, string clientIp)
        {
            string   availabilityId       = default;
            DateTime?availabilityDeadline = default;
            DateTime availabilityCheckIn  = default;
            string   referenceCode        = default;
            var      wasPaymentMade       = false;
            var      settings             = await _accommodationBookingSettingsService.Get(agentContext);

            // TODO Remove lots of code duplication in account and card purchase booking
            var(_, isRegisterFailure, booking, registerError) = await GetCachedAvailability(bookingRequest, agentContext)
                                                                .Ensure(AreAprSettingsSuitable, ProblemDetailsBuilder.Build("You can't book the restricted contract without explicit approval from a Happytravel.com officer."))
                                                                .Ensure(AreDeadlineSettingsSuitable, ProblemDetailsBuilder.Build("You can't book the contract within deadline without explicit approval from a Happytravel.com officer."))
                                                                .Tap(FillAvailabilityLocalVariables)
                                                                .Map(ExtractBookingAvailabilityInfo)
                                                                .BindWithTransaction(_context, info => Result.Success <BookingAvailabilityInfo, ProblemDetails>(info)
                                                                                     .Map(RegisterBooking)
                                                                                     .Bind(GetBooking)
                                                                                     .Bind(PayUsingAccountIfDeadlinePassed))
                                                                .OnFailure(WriteLogFailure);

            if (isRegisterFailure)
            {
                return(Result.Failure <AccommodationBookingInfo, ProblemDetails>(registerError));
            }

            return(await BookOnProvider(booking, booking.ReferenceCode, languageCode)
                   .Tap(ProcessResponse)
                   .OnFailure(VoidMoneyAndCancelBooking)
                   .Bind(GenerateInvoice)
                   .Bind(SendReceiptIfPaymentMade)
                   .Bind(GetAccommodationBookingInfo)
                   .Finally(WriteLog));


            void FillAvailabilityLocalVariables((Suppliers, DataWithMarkup <RoomContractSetAvailability> Result) responseWithMarkup)
            {
                availabilityId       = responseWithMarkup.Result.Data.AvailabilityId;
                availabilityDeadline = responseWithMarkup.Result.Data.RoomContractSet.Deadline.Date;
                availabilityCheckIn  = responseWithMarkup.Result.Data.CheckInDate;
            }

            bool AreAprSettingsSuitable(
                (Suppliers, DataWithMarkup <RoomContractSetAvailability>) bookingData)
            => BookingRegistrationService.AreAprSettingsSuitable(bookingRequest, bookingData, settings);


            bool AreDeadlineSettingsSuitable(
                (Suppliers, DataWithMarkup <RoomContractSetAvailability>) bookingData)
            => this.AreDeadlineSettingsSuitable(bookingRequest, bookingData, settings);


            async Task <string> RegisterBooking(BookingAvailabilityInfo bookingAvailability)
            {
                var bookingRequestWithAvailabilityId = new AccommodationBookingRequest(bookingRequest, availabilityId);
                var registeredReferenceCode          =
                    await _bookingRecordsManager.Register(bookingRequestWithAvailabilityId, bookingAvailability, agentContext, languageCode);

                referenceCode = registeredReferenceCode;
                return(registeredReferenceCode);
            }

            async Task <Result <Data.Booking.Booking, ProblemDetails> > GetBooking(string referenceCode)
            => await _bookingRecordsManager.Get(referenceCode).ToResultWithProblemDetails();


            async Task <Result <Data.Booking.Booking, ProblemDetails> > PayUsingAccountIfDeadlinePassed(Data.Booking.Booking bookingInPipeline)
            {
                var daysBeforeDeadline = Infrastructure.Constants.Common.DaysBeforeDeadlineWhenPayForBooking;
                var now = _dateTimeProvider.UtcNow();

                var deadlinePassed = availabilityCheckIn <= now.AddDays(daysBeforeDeadline) ||
                                     (availabilityDeadline.HasValue && availabilityDeadline <= now.AddDays(daysBeforeDeadline));

                if (!deadlinePassed)
                {
                    return(bookingInPipeline);
                }

                var(_, isPaymentFailure, _, paymentError) = await _accountPaymentService.Charge(bookingInPipeline, agentContext, clientIp);

                if (isPaymentFailure)
                {
                    return(ProblemDetailsBuilder.Fail <Data.Booking.Booking>(paymentError));
                }

                wasPaymentMade = true;
                return(bookingInPipeline);
            }

            Task ProcessResponse(EdoContracts.Accommodations.Booking bookingResponse) => _bookingResponseProcessor.ProcessResponse(bookingResponse, booking);

            Task VoidMoneyAndCancelBooking(ProblemDetails problemDetails) => this.VoidMoneyAndCancelBooking(booking, agentContext);

            Task <Result <EdoContracts.Accommodations.Booking, ProblemDetails> > GenerateInvoice(EdoContracts.Accommodations.Booking details) => this.GenerateInvoice(details, booking.ReferenceCode, agentContext);


            async Task <Result <EdoContracts.Accommodations.Booking, ProblemDetails> > SendReceiptIfPaymentMade(EdoContracts.Accommodations.Booking details)
            => wasPaymentMade
                    ? await SendReceipt(details, booking, agentContext)
                    : details;


            Task <Result <AccommodationBookingInfo, ProblemDetails> > GetAccommodationBookingInfo(EdoContracts.Accommodations.Booking details)
            => _bookingRecordsManager.GetAccommodationBookingInfo(details.ReferenceCode, languageCode)
            .ToResultWithProblemDetails();


            void WriteLogFailure(ProblemDetails problemDetails)
            => _logger.LogBookingByAccountFailure($"Failed to book using account. Reference code: '{referenceCode}'. Error: {problemDetails.Detail}");


            Result <T, ProblemDetails> WriteLog <T>(Result <T, ProblemDetails> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingFinalizationSuccess($"Successfully booked using account. Reference code: '{referenceCode}'"),
                                            () => _logger.LogBookingFinalizationFailure(
                                                $"Failed to book using account. Reference code: '{referenceCode}'. Error: {result.Error.Detail}"));
        }
Esempio n. 14
0
        public async Task <string> Register(AccommodationBookingRequest bookingRequest,
                                            BookingAvailabilityInfo availabilityInfo, AgentContext agentContext, string languageCode)
        {
            var(_, _, booking, _) = await Result.Success()
                                    .Map(GetTags)
                                    .Map(Create);

            return(booking.ReferenceCode);


            async Task <(string itn, string referenceCode)> GetTags()
            {
                string itn;

                if (string.IsNullOrWhiteSpace(bookingRequest.ItineraryNumber))
                {
                    itn = await _tagProcessor.GenerateItn();
                }
                else
                {
                    // User can send reference code instead of itn
                    if (!_tagProcessor.TryGetItnFromReferenceCode(bookingRequest.ItineraryNumber, out itn))
                    {
                        itn = bookingRequest.ItineraryNumber;
                    }

                    if (!await AreExistBookingsForItn(itn, agentContext.AgentId))
                    {
                        itn = await _tagProcessor.GenerateItn();
                    }
                }

                var referenceCode = await _tagProcessor.GenerateReferenceCode(
                    ServiceTypes.HTL,
                    availabilityInfo.CountryCode,
                    itn);

                return(itn, referenceCode);
            }

            async Task <Data.Booking.Booking> Create((string itn, string referenceCode) tags)
            {
                var createdBooking = BookingFactory.Create(
                    _dateTimeProvider.UtcNow(),
                    agentContext,
                    tags.itn,
                    tags.referenceCode,
                    availabilityInfo,
                    bookingRequest.PaymentMethod,
                    bookingRequest,
                    languageCode,
                    availabilityInfo.Supplier,
                    availabilityInfo.RoomContractSet.Deadline.Date,
                    availabilityInfo.CheckInDate,
                    availabilityInfo.CheckOutDate);

                _context.Bookings.Add(createdBooking);
                await _context.SaveChangesAsync();

                _context.Entry(createdBooking).State = EntityState.Detached;

                return(createdBooking);
            }
        }
Esempio n. 15
0
        public async Task <Result <Booking> > Register(AccommodationBookingRequest bookingRequest,
                                                       BookingAvailabilityInfo availabilityInfo, PaymentTypes paymentMethod, AgentContext agentContext, string languageCode)
        {
            var(_, isFailure, booking, error) = await CheckRooms()
                                                .Map(GetTags)
                                                .Map(Create)
                                                .Tap(SaveRequestInfo)
                                                .Tap(LogBookingStatus)
                                                .Tap(SaveMarkups)
                                                .Tap(CreateSupplierOrder);

            if (isFailure)
            {
                return(Result.Failure <Booking>(error));
            }

            _logger.LogBookingRegistrationSuccess(booking.ReferenceCode);
            return(booking);


            Result CheckRooms()
            {
                if (bookingRequest.RoomDetails.Count != availabilityInfo.AvailabilityRequest.RoomDetails.Count)
                {
                    return(Result.Failure("Rooms does not correspond to search rooms"));
                }

                for (var i = 0; i < bookingRequest.RoomDetails.Count; i++)
                {
                    var adultsCount   = bookingRequest.RoomDetails[i].Passengers.Count(p => p.Age == null);
                    var childrenCount = bookingRequest.RoomDetails[i].Passengers.Count(p => p.Age != null);

                    if (availabilityInfo.AvailabilityRequest.RoomDetails[i].AdultsNumber != adultsCount ||
                        availabilityInfo.AvailabilityRequest.RoomDetails[i].ChildrenAges.Count != childrenCount)
                    {
                        return(Result.Failure("Rooms does not correspond to search rooms"));
                    }
                }

                return(Result.Success());
            }

            async Task <(string itn, string referenceCode)> GetTags()
            {
                string itn;

                if (string.IsNullOrWhiteSpace(bookingRequest.ItineraryNumber))
                {
                    itn = await _tagProcessor.GenerateItn();
                }
                else
                {
                    // User can send reference code instead of itn
                    if (!_tagProcessor.TryGetItnFromReferenceCode(bookingRequest.ItineraryNumber, out itn))
                    {
                        itn = bookingRequest.ItineraryNumber;
                    }

                    if (!await AreExistBookingsForItn(itn, agentContext.AgentId))
                    {
                        itn = await _tagProcessor.GenerateItn();
                    }
                }

                var referenceCode = await _tagProcessor.GenerateReferenceCode(
                    ServiceTypes.HTL,
                    availabilityInfo.CountryCode,
                    itn);

                return(itn, referenceCode);
            }

            async Task <Booking> Create((string itn, string referenceCode) tags)
            {
                var createdBooking = await CreateBooking(
                    created : _dateTimeProvider.UtcNow(),
                    agentContext : agentContext,
                    itineraryNumber : tags.itn,
                    referenceCode : tags.referenceCode,
                    clientReferenceCode : bookingRequest.ClientReferenceCode,
                    availabilityInfo : availabilityInfo,
                    paymentMethod : paymentMethod,
                    bookingRequest : bookingRequest,
                    languageCode : languageCode);

                _context.Bookings.Add(createdBooking);
                await _context.SaveChangesAsync();

                _context.Entry(createdBooking).State = EntityState.Detached;

                return(createdBooking);
            }

            Task SaveRequestInfo(Booking booking)
            => _requestStorage.Set(booking.ReferenceCode, bookingRequest, availabilityInfo);


            Task LogBookingStatus(Booking booking)
            {
                var changeReason = new BookingChangeReason
                {
                    Event  = BookingChangeEvents.Create,
                    Source = BookingChangeSources.System
                };

                return(_changeLogService.Write(booking, BookingStatuses.Created, booking.Created.DateTime,
                                               agentContext.ToApiCaller(), changeReason));
            }

            Task SaveMarkups(Booking booking)
            => _appliedBookingMarkupRecordsManager.Create(booking.ReferenceCode, availabilityInfo.AppliedMarkups);


            Task CreateSupplierOrder(Booking booking)
            => _supplierOrderService.Add(referenceCode: booking.ReferenceCode,
                                         serviceType: ServiceTypes.HTL,
                                         convertedPrice: availabilityInfo.ConvertedSupplierPrice,
                                         supplierPrice: availabilityInfo.OriginalSupplierPrice,
                                         deadline: availabilityInfo.SupplierDeadline,
                                         supplier: (int)booking.Supplier,
                                         paymentType: availabilityInfo.CardRequirement is not null
                        ? SupplierPaymentType.CreditCard
                        : SupplierPaymentType.DirectPayment,
                                         paymentDate: availabilityInfo.RoomContractSet.IsAdvancePurchaseRate
                        ? booking.Created.DateTime
                        : booking.CheckOutDate.DateTime);
        }
Esempio n. 16
0
        private async Task <Booking> CreateBooking(DateTime created, AgentContext agentContext, string itineraryNumber,
                                                   string referenceCode, string clientReferenceCode, BookingAvailabilityInfo availabilityInfo, PaymentTypes paymentMethod,
                                                   AccommodationBookingRequest bookingRequest, string languageCode)
        {
            var booking = new Booking
            {
                Created             = created,
                ItineraryNumber     = itineraryNumber,
                ReferenceCode       = referenceCode,
                ClientReferenceCode = clientReferenceCode,
                Status                = BookingStatuses.Created,
                PaymentType           = paymentMethod,
                LanguageCode          = languageCode,
                Supplier              = availabilityInfo.Supplier,
                PaymentStatus         = BookingPaymentStatuses.NotPaid,
                DeadlineDate          = availabilityInfo.RoomContractSet.Deadline.Date,
                CheckInDate           = availabilityInfo.CheckInDate,
                CheckOutDate          = availabilityInfo.CheckOutDate,
                HtId                  = availabilityInfo.HtId,
                Tags                  = availabilityInfo.RoomContractSet.Tags,
                IsDirectContract      = availabilityInfo.RoomContractSet.IsDirectContract,
                CancellationPolicies  = availabilityInfo.RoomContractSet.Deadline.Policies,
                IsAdvancePurchaseRate = availabilityInfo.RoomContractSet.IsAdvancePurchaseRate,
                IsPackage             = availabilityInfo.RoomContractSet.IsPackageRate
            };

            AddRequestInfo(bookingRequest);
            AddServiceDetails();
            AddAgentInfo();
            AddRooms(availabilityInfo.RoomContractSet.Rooms, bookingRequest.RoomDetails);
            booking = await AddStaticData(booking, availabilityInfo);

            return(booking);


            void AddRequestInfo(in AccommodationBookingRequest bookingRequestInternal)
            {
                booking.Nationality       = availabilityInfo.AvailabilityRequest.Nationality.ToUpper();
                booking.Residency         = availabilityInfo.AvailabilityRequest.Residency.ToUpper();
                booking.MainPassengerName = bookingRequestInternal.MainPassengerName.Trim();
            }

            void AddServiceDetails()
            {
                var rate = availabilityInfo.RoomContractSet.Rate;

                booking.TotalPrice = rate.FinalPrice.Amount;
                booking.Currency   = rate.Currency;
            }

            void AddAgentInfo()
            {
                booking.AgentId  = agentContext.AgentId;
                booking.AgencyId = agentContext.AgencyId;
            }

            void AddRooms(List <RoomContract> roomContracts, List <BookingRoomDetails> bookingRequestRoomDetails)
            {
                booking.Rooms = roomContracts
                                .Select((r, number) =>
                                        new BookedRoom(r.Type,
                                                       r.IsExtraBedNeeded,
                                                       r.Rate.FinalPrice,
                                                       r.BoardBasis,
                                                       r.MealPlan,
                                                       r.Deadline.Date,
                                                       r.ContractDescription,
                                                       r.Remarks,
                                                       r.Deadline,
                                                       GetCorrespondingPassengers(number),
                                                       r.IsAdvancePurchaseRate,
                                                       string.Empty))
                                .ToList();


                List <Passenger> GetCorrespondingPassengers(int number)
                => bookingRequestRoomDetails[number].Passengers
                .Select(p => new Passenger(p.Title, p.LastName.Trim(), p.FirstName.Trim(), p.IsLeader, p.Age))
                .ToList();
            }
        }