public async Task ProcessConfirmation(Data.Booking.Booking booking, EdoContracts.Accommodations.Booking bookingResponse) { await GetBookingInfo(booking.ReferenceCode, booking.LanguageCode) .Tap(Confirm) .Tap(NotifyBookingFinalization) .Bind(SendInvoice) .OnFailure(WriteFailureLog); Task <Result <AccommodationBookingInfo> > GetBookingInfo(string referenceCode, string languageCode) => _bookingRecordsManager .GetAccommodationBookingInfo(referenceCode, languageCode); Task Confirm(AccommodationBookingInfo bookingInfo) => _bookingRecordsManager.Confirm(bookingResponse, booking); Task NotifyBookingFinalization(AccommodationBookingInfo bookingInfo) => _bookingMailingService .NotifyBookingFinalized(bookingInfo); Task <Result> SendInvoice(AccommodationBookingInfo bookingInfo) => _bookingMailingService .SendInvoice(bookingInfo.BookingId, bookingInfo.AgentInformation.AgentEmail, booking.AgentId); void WriteFailureLog(string error) => _logger .LogBookingConfirmationFailure($"Booking '{booking.ReferenceCode} confirmation failed: '{error}"); // TODO: Revert supplier order placing NIJO-1015 // await SaveSupplierOrder(); // // async Task SaveSupplierOrder() // { // var supplierPrice = bookingResponse.RoomContractSet.Price.NetTotal; // await _supplierOrderService.Add(bookingResponse.ReferenceCode, ServiceTypes.HTL, supplierPrice); // } }
public async Task ProcessResponse(Booking bookingResponse, Data.Booking.Booking booking) { await _bookingAuditLogService.Add(bookingResponse, booking); _logger.LogBookingResponseProcessStarted( $"Start the booking response processing with the reference code '{bookingResponse.ReferenceCode}'. Old status: {booking.Status}"); if (bookingResponse.Status == BookingStatusCodes.NotFound) { await _bookingChangesProcessor.ProcessBookingNotFound(booking, bookingResponse); return; } if (bookingResponse.Status.ToInternalStatus() == booking.Status) { _logger.LogBookingResponseProcessSuccess( $"The booking response with the reference code '{bookingResponse.ReferenceCode}' has been successfully processed. No changes applied"); return; } await UpdateBookingDetails(); switch (bookingResponse.Status) { case BookingStatusCodes.Confirmed: await _bookingChangesProcessor.ProcessConfirmation(booking, bookingResponse); break; case BookingStatusCodes.Cancelled: await _bookingChangesProcessor.ProcessCancellation(booking, UserInfo.InternalServiceAccount); break; } _logger.LogBookingResponseProcessSuccess( $"The booking response with the reference code '{bookingResponse.ReferenceCode}' has been successfully processed. " + $"New status: {bookingResponse.Status}"); Task UpdateBookingDetails() => _bookingRecordsManager.UpdateBookingDetails(bookingResponse, booking); //TICKET https://happytravel.atlassian.net/browse/NIJO-315 /* * async Task<Result> LogAppliedMarkups() * { * long availabilityId = ??? ; * * var (_, isGetAvailabilityFailure, responseWithMarkup, cachedAvailabilityError) = await _availabilityResultsCache.Get(availabilityId); * if (isGetAvailabilityFailure) * return Result.Fail(cachedAvailabilityError); * * await _markupLogger.Write(bookingResponse.ReferenceCode, ServiceTypes.HTL, responseWithMarkup.AppliedPolicies); * return Result.Success(); * } */ }
// TODO: Remove room information and contract description from booking NIJO-915 static EdoContracts.Accommodations.Booking GetStubDetails(Data.Booking.Booking booking) => new EdoContracts.Accommodations.Booking(booking.ReferenceCode, // Will be set in the refresh step BookingStatusCodes.WaitingForResponse, booking.AccommodationId, booking.SupplierReferenceCode, booking.CheckInDate, booking.CheckOutDate, new List <SlimRoomOccupation>(0), BookingUpdateModes.Asynchronous);
public async Task ProcessBookingNotFound(Data.Booking.Booking booking, EdoContracts.Accommodations.Booking bookingResponse) { if (_dateTimeProvider.UtcNow() < booking.Created + BookingCheckTimeout) { _logger.LogBookingResponseProcessSuccess( $"The booking response with the reference code '{bookingResponse.ReferenceCode}' has not been processed due to '{BookingStatusCodes.NotFound}' status."); } else { await _bookingRecordsManager.SetNeedsManualCorrectionStatus(booking); _logger.LogBookingResponseProcessSuccess( $"The booking response with the reference code '{bookingResponse.ReferenceCode}' set as needed manual processing."); } }
public Task <Result> ProcessCancellation(Data.Booking.Booking booking, UserInfo user) { return(SendNotifications() .Tap(CancelSupplierOrder) .Bind(VoidMoney) .Tap(SetBookingCancelled)); async Task CancelSupplierOrder() { var referenceCode = booking.ReferenceCode; await _supplierOrderService.Cancel(referenceCode); } async Task <Result> SendNotifications() { var agent = await _context.Agents.SingleOrDefaultAsync(a => a.Id == booking.AgentId); if (agent == default) { _logger.LogWarning("Booking cancellation notification: could not find agent with id '{0}' for the booking '{1}'", booking.AgentId, booking.ReferenceCode); return(Result.Success()); } var(_, _, bookingInfo, _) = await _bookingRecordsManager.GetAccommodationBookingInfo(booking.ReferenceCode, booking.LanguageCode); await _bookingMailingService.NotifyBookingCancelled(bookingInfo); return(Result.Success()); } async Task <Result> VoidMoney() { if (booking.PaymentStatus == BookingPaymentStatuses.Authorized || booking.PaymentStatus == BookingPaymentStatuses.Captured) { return(await _paymentService.VoidOrRefund(booking, user)); } return(Result.Success()); } Task SetBookingCancelled() => _bookingRecordsManager.ConfirmBookingCancellation(booking); }
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 <EdoContracts.Accommodations.Booking, ProblemDetails> > BookOnProvider(Data.Booking.Booking booking, string referenceCode, string languageCode) { // TODO: will be implemented in NIJO-31 var bookingRequest = JsonConvert.DeserializeObject <AccommodationBookingRequest>(booking.BookingRequest); var features = new List <Feature>(); //bookingRequest.Features var roomDetails = bookingRequest.RoomDetails .Select(d => new SlimRoomOccupation(d.Type, d.Passengers, string.Empty, d.IsExtraBedNeeded)) .ToList(); var innerRequest = new BookingRequest(bookingRequest.AvailabilityId, bookingRequest.RoomContractSetId, booking.ReferenceCode, roomDetails, features, bookingRequest.RejectIfUnavailable); try { var bookingResult = await _supplierConnectorManager .Get(booking.Supplier) .Book(innerRequest, languageCode); if (bookingResult.IsSuccess) { return(bookingResult.Value); } // If result is failed this does not mean that booking failed. This means that we should check it later. _logger.LogBookingFinalizationFailure($"The booking finalization with the reference code: '{referenceCode}' has been failed"); return(GetStubDetails(booking)); } catch { var errorMessage = $"Failed to update booking data (refcode '{referenceCode}') after the request to the connector"; var(_, isCancellationFailed, cancellationError) = await _supplierConnectorManager.Get(booking.Supplier).CancelBooking(booking.ReferenceCode); if (isCancellationFailed) { errorMessage += Environment.NewLine + $"Booking cancellation has failed: {cancellationError}"; } _logger.LogBookingFinalizationFailure(errorMessage); return(GetStubDetails(booking)); }
private async Task <Result <EdoContracts.Accommodations.Booking, ProblemDetails> > SendReceipt(EdoContracts.Accommodations.Booking details, Data.Booking.Booking booking, AgentContext agentContext) { var(_, isReceiptFailure, receiptInfo, receiptError) = await _documentsService.GenerateReceipt(booking.Id, agentContext.AgentId); if (isReceiptFailure) { return(ProblemDetailsBuilder.Fail <EdoContracts.Accommodations.Booking>(receiptError)); } await _notificationService.SendReceiptToCustomer(receiptInfo, agentContext.Email); return(Result.Success <EdoContracts.Accommodations.Booking, ProblemDetails>(details)); }