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));
        }
Exemple #2
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));
        }
        public async Task <Result> Cancel(Booking booking, ApiCaller apiCaller, BookingChangeEvents eventType)
        {
            if (booking.Status == BookingStatuses.Cancelled)
            {
                _logger.LogBookingAlreadyCancelled(booking.ReferenceCode);
                return(Result.Success());
            }

            return(await CheckBookingCanBeCancelled()
                   .Bind(SendCancellationRequest)
                   .Bind(ProcessCancellation)
                   .Finally(WriteLog));


            Result CheckBookingCanBeCancelled()
            {
                if (booking.Status != BookingStatuses.Confirmed)
                {
                    return(Result.Failure("Only confirmed bookings can be cancelled"));
                }

                if (booking.CheckOutDate <= _dateTimeProvider.UtcToday())
                {
                    return(Result.Failure("Cannot cancel booking after check out date"));
                }

                return(Result.Success());
            }

            async Task <Result <Booking> > SendCancellationRequest()
            {
                var(_, isCancelFailure, _, cancelError) = await _supplierConnectorManager.Get((Suppliers)booking.Supplier).CancelBooking(booking.ReferenceCode);

                return(isCancelFailure
                    ? Result.Failure <Booking>(cancelError.Detail)
                    : Result.Success(booking));
            }

            async Task <Result> ProcessCancellation(Booking b)
            {
                var changeReason = new BookingChangeReason
                {
                    Event  = eventType,
                    Source = BookingChangeSources.System
                };

                await _bookingRecordsUpdater.ChangeStatus(b, BookingStatuses.PendingCancellation, _dateTimeProvider.UtcNow(), apiCaller, changeReason);

                return(b.UpdateMode == BookingUpdateModes.Synchronous
                    ? await RefreshStatus(b, apiCaller, eventType)
                    : Result.Success());
            }

            Result WriteLog(Result result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingCancelSuccess(booking.ReferenceCode),
                                            () => _logger.LogBookingCancelFailure(booking.ReferenceCode, result.Error));
        }
Exemple #4
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}"));
        }
Exemple #5
0
        private async Task <Result <VoidObject, ProblemDetails> > CancelBooking(Data.Booking.Booking booking, UserInfo user,
                                                                                bool requireProviderConfirmation = true)
        {
            if (booking.Status == BookingStatuses.Cancelled)
            {
                _logger.LogBookingAlreadyCancelled(
                    $"Skipping cancellation for a booking with reference code: '{booking.ReferenceCode}'. Already cancelled.");

                return(Result.Success <VoidObject, ProblemDetails>(VoidObject.Instance));
            }

            return(await SendCancellationRequest()
                   .Bind(ProcessCancellation)
                   .Finally(WriteLog));


            async Task <Result <Data.Booking.Booking, ProblemDetails> > SendCancellationRequest()
            {
                var(_, isCancelFailure, _, cancelError) = await _supplierConnectorManager.Get(booking.Supplier).CancelBooking(booking.ReferenceCode);

                return(isCancelFailure && requireProviderConfirmation
                    ? Result.Failure <Data.Booking.Booking, ProblemDetails>(cancelError)
                    : Result.Success <Data.Booking.Booking, ProblemDetails>(booking));
            }

            async Task <Result <VoidObject, ProblemDetails> > ProcessCancellation(Data.Booking.Booking b)
            {
                if (b.UpdateMode == BookingUpdateModes.Synchronous || !requireProviderConfirmation)
                {
                    return(await _bookingChangesProcessor.ProcessCancellation(b, user).ToResultWithProblemDetails());
                }

                return(VoidObject.Instance);
            }

            Result <T, ProblemDetails> WriteLog <T>(Result <T, ProblemDetails> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingCancelSuccess($"Successfully cancelled a booking with reference code: '{booking.ReferenceCode}'"),
                                            () => _logger.LogBookingCancelFailure(
                                                $"Failed to cancel a booking with reference code: '{booking.ReferenceCode}'. Error: {result.Error.Detail}"));
        }
Exemple #6
0
        private async Task <Result <TResult, ProblemDetails> > ExecuteWithLogging <TResult>(string step, Func <Task <Result <TResult, ProblemDetails> > > funcToExecute)
        {
            _logger.LogSupplierConnectorRequestStarted(_baseUrl, step);

            using var timer = Counters.SupplierRequestHistogram.WithLabels(step, _supplier.ToString()).NewTimer();
            var result = await funcToExecute();

            timer.Dispose();

            Counters.SupplierRequestCounter
            .WithLabels(step,
                        _supplier.ToString(),
                        result.IsFailure ? result.Error.Status.ToString() : string.Empty)
            .Inc();

            LoggerUtils.WriteLogByResult(result,
                                         () => _logger.LogSupplierConnectorRequestSuccess(_baseUrl, step),
                                         () => _logger.LogSupplierConnectorRequestError(_baseUrl, result.Error.Detail, step, result.Error.Status));

            return(result);
        }
        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));
        }
Exemple #8
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}"));
        }
Exemple #9
0
        public async Task <Result <AccommodationBookingInfo, ProblemDetails> > Finalize(string referenceCode, AgentContext agentContext, string languageCode)
        {
            var(_, isGetBookingFailure, booking, getBookingError) = await GetAgentsBooking()
                                                                    .Ensure(b => agentContext.AgencyId == b.AgencyId, ProblemDetailsBuilder.Build("The booking does not belong to your current agency"))
                                                                    .Bind(CheckBookingIsPaid)
                                                                    .OnFailure(WriteLogFailure);

            if (isGetBookingFailure)
            {
                return(Result.Failure <AccommodationBookingInfo, ProblemDetails>(getBookingError));
            }

            return(await BookOnProvider(booking, referenceCode, languageCode)
                   .Tap(ProcessResponse)
                   .Bind(CaptureMoneyIfDeadlinePassed)
                   .OnFailure(VoidMoneyAndCancelBooking)
                   .Bind(GenerateInvoice)
                   .Tap(NotifyOnCreditCardPayment)
                   .Bind(GetAccommodationBookingInfo)
                   .Finally(WriteLog));


            Task <Result <Data.Booking.Booking, ProblemDetails> > GetAgentsBooking()
            => _bookingRecordsManager.GetAgentsBooking(referenceCode, agentContext).ToResultWithProblemDetails();


            Result <Data.Booking.Booking, ProblemDetails> CheckBookingIsPaid(Data.Booking.Booking bookingFromPipe)
            {
                if (bookingFromPipe.PaymentStatus == BookingPaymentStatuses.NotPaid)
                {
                    _logger.LogBookingFinalizationPaymentFailure($"The booking with reference code: '{referenceCode}' hasn't been paid");
                    return(ProblemDetailsBuilder.Fail <Data.Booking.Booking>("The booking hasn't been paid"));
                }

                return(bookingFromPipe);
            }

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


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

                var deadlinePassed = booking.CheckInDate <= now.AddDays(daysBeforeDeadline) ||
                                     (booking.DeadlineDate.HasValue && booking.DeadlineDate.Value.Date <= now.AddDays(daysBeforeDeadline));

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

                var(_, isPaymentFailure, _, paymentError) = await _bookingPaymentService.Capture(booking, agentContext.ToUserInfo());

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

                return(bookingInPipeline);
            }

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


            async Task <Result <Booking, ProblemDetails> > NotifyOnCreditCardPayment(Booking details)
            {
                await _bookingMailingService.SendCreditCardPaymentNotifications(details.ReferenceCode);

                return(details);
            }

            Task <Result <Booking, ProblemDetails> > GenerateInvoice(Booking details) => this.GenerateInvoice(details, referenceCode, agentContext);


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


            void WriteLogFailure(ProblemDetails problemDetails)
            => _logger.LogBookingByAccountFailure($"Failed to finalize a booking with reference code: '{referenceCode}'. Error: {problemDetails.Detail}");


            Result <T, ProblemDetails> WriteLog <T>(Result <T, ProblemDetails> result)
            => LoggerUtils.WriteLogByResult(result,
                                            () => _logger.LogBookingFinalizationSuccess($"Successfully finalized a booking with reference code: '{referenceCode}'"),
                                            () => _logger.LogBookingFinalizationFailure(
                                                $"Failed to finalize a booking with reference code: '{referenceCode}'. Error: {result.Error.Detail}"));
        }
Exemple #10
0
 Result <PaymentResponse> WriteLog(Result <PaymentResponse> result)
 {
     return(LoggerUtils.WriteLogByResult(result,
                                         () => _logger.LogCreditCardAuthorizationSuccess(request.ReferenceCode),
                                         () => _logger.LogCreditCardAuthorizationFailure(request.ReferenceCode, result.Error)));
 }
        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));
        }