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)); }
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)); }