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