Ejemplo n.º 1
0
        public async Task <Result <Booking> > Execute(Data.Bookings.Booking booking, AgentContext agent, string languageCode)
        {
            Baggage.AddBookingReferenceCode(booking.ReferenceCode);

            var requestInfoResult = await _requestStorage.Get(booking.ReferenceCode);

            if (requestInfoResult.IsFailure)
            {
                return(Result.Failure <Booking>(requestInfoResult.Error));
            }

            var(bookingRequest, availabilityInfo) = requestInfoResult.Value;
            var creditCardResult = await GetCreditCard(booking, availabilityInfo);

            if (creditCardResult.IsFailure)
            {
                return(Result.Failure <Booking>(creditCardResult.Error));
            }

            var bookingRequestResult = await SendSupplierRequest(bookingRequest, availabilityInfo.AvailabilityId, booking, creditCardResult.Value, languageCode);

            if (bookingRequestResult.IsSuccess)
            {
                _bookingAnalyticsService.LogBookingOccured(bookingRequest, booking, agent);
            }

            await ProcessRequestResult(bookingRequestResult);

            return(bookingRequestResult);

            async Task <Result <Booking> > SendSupplierRequest(AccommodationBookingRequest bookingRequest, string availabilityId,
                                                               Data.Bookings.Booking booking, CreditCardInfo creditCard, string languageCode)
            {
                var features = new List <Feature>();

                var roomDetails = bookingRequest.RoomDetails
                                  .Select(d => new SlimRoomOccupation(d.Type, d.Passengers, string.Empty, d.IsExtraBedNeeded))
                                  .ToList();

                var creditCardInfo = creditCard is not null
                    ? new CreditCard(creditCard.Number, creditCard.ExpiryDate, creditCard.HolderName, creditCard.SecurityCode, CardVendor.AmericanExpress)
                    : (CreditCard?)null;

                var innerRequest = new BookingRequest(availabilityId: availabilityId,
                                                      roomContractSetId: bookingRequest.RoomContractSetId,
                                                      referenceCode: booking.ReferenceCode,
                                                      rooms: roomDetails,
                                                      features: features,
                                                      creditCard: creditCardInfo,
                                                      rejectIfUnavailable: bookingRequest.RejectIfUnavailable);

                try
                {
                    var(isSuccess, _, bookingResult, error) = await TimeObserver.Execute(observedFunc : () => _supplierConnectorManager
                                                                                         .Get((Suppliers)booking.Supplier)
                                                                                         .Book(innerRequest, languageCode),
                                                                                         notifyFunc : Notify,
                                                                                         notifyAfter : TimeSpan.FromSeconds(BookExecutionTimeLimitInSeconds));

                    if (isSuccess)
                    {
                        return(bookingResult);
                    }

                    var message = error.Detail;
                    // If result is failed this does not mean that booking failed. All known cases are listed below
                    _logger.LogBookingFinalizationFailure(booking.ReferenceCode, message);

                    if (!error.Extensions.TryGetBookingFailureCode(out var failureCode))
                    {
                        // We do not know whether booking was registered on supplier
                        return(GetStubDetails(booking));
                    }

                    return(failureCode switch
                    {
                        // We are sure that booking was not done
                        BookingFailureCodes.ConnectorValidationFailed => Result.Failure <Booking>(message),
                        BookingFailureCodes.ValuationResultNotFound => Result.Failure <Booking>(message),
                        BookingFailureCodes.PreBookingFailed => Result.Failure <Booking>(message),
                        BookingFailureCodes.SupplierValidationFailed => Result.Failure <Booking>(message),
                        BookingFailureCodes.SupplierRejected => Result.Failure <Booking>(message),

                        // We do not know whether booking was registered on supplier
                        _ => GetStubDetails(booking)
                    });


                    Task Notify()
                    {
                        _logger.LogBookingExceededTimeLimit(innerRequest.ReferenceCode);
                        return(Task.CompletedTask);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogBookingFinalizationException(ex);
                    return(GetStubDetails(booking));
                }
Ejemplo n.º 2
0
        public async Task <Result <AccommodationBookingInfo> > Finalize(string referenceCode, AgentContext agentContext, string languageCode)
        {
            return(await GetBooking()
                   .Check(CheckBookingIsPaid)
                   .CheckIf(IsDeadlinePassed, CaptureMoney)
                   .Check(GenerateInvoice)
                   .Bind(SendSupplierRequest)
                   .Bind(NotifyPaymentReceived)
                   .Bind(GetAccommodationBookingInfo)
                   .Finally(WriteLog));


            Task <Result <Booking> > GetBooking()
            => _bookingInfoService.GetAgentsBooking(referenceCode, agentContext);


            Result CheckBookingIsPaid(Booking bookingFromPipe)
            {
                if (bookingFromPipe.PaymentStatus != BookingPaymentStatuses.Authorized)
                {
                    _logger.LogBookingFinalizationPaymentFailure(referenceCode);
                    return(Result.Failure <Booking>("The booking hasn't been paid"));
                }

                return(Result.Success());
            }

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


            async Task <Result> CaptureMoney(Booking booking)
            => await _creditCardPaymentService.Capture(booking, agentContext.ToApiCaller());


            async Task <Result <EdoContracts.Accommodations.Booking> > SendSupplierRequest(Data.Bookings.Booking booking)
            {
                var(_, isFailure, requestInfo, error) = await _requestStorage.Get(booking.ReferenceCode);

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

                var(request, availabilityInfo) = requestInfo;
                Baggage.AddSearchId(request.SearchId);
                Baggage.AddBookingReferenceCode(booking.ReferenceCode);

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

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


            async Task <Result <EdoContracts.Accommodations.Booking> > NotifyPaymentReceived(EdoContracts.Accommodations.Booking details)
            {
                await _bookingNotificationService.NotifyCreditCardPaymentConfirmed(details.ReferenceCode);

                return(details);
            }

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


            Result <AccommodationBookingInfo> WriteLog(Result <AccommodationBookingInfo> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingFinalizationSuccess(result.Value.BookingDetails.ReferenceCode),
                                            () => _logger.LogBookingFinalizationFailure(referenceCode, result.Error));
        }