public Task <Result <BatchOperationResult> > Capture(List <int> bookingIds, ServiceAccount serviceAccount) { return(ExecuteBatchAction(bookingIds, IsBookingValidForCapturePredicate, Capture, serviceAccount)); Task <Result <string> > Capture(Booking booking, ApiCaller serviceAcc) => _creditCardPaymentService.Capture(booking, serviceAccount.ToApiCaller()); }
public Task <Result <BatchOperationResult> > Cancel(List <int> bookingIds, ServiceAccount serviceAccount) { return(ExecuteBatchAction(bookingIds, IsBookingValidForCancelPredicate, ProcessBooking, serviceAccount)); Task <Result <string> > ProcessBooking(Booking booking, ApiCaller _) { return(_supplierBookingManagementService.Cancel(booking, serviceAccount.ToApiCaller(), BookingChangeEvents.Cancel) .Finally(CreateResult)); Result <string> CreateResult(Result result) => result.IsSuccess ? Result.Success($"Booking '{booking.ReferenceCode}' was cancelled.") : Result.Failure <string>($"Unable to cancel booking '{booking.ReferenceCode}'. Reason: {result.Error}"); } }
public Task <Result <BatchOperationResult> > Charge(List <int> bookingIds, ServiceAccount serviceAccount) { return(ExecuteBatchAction(bookingIds, IsBookingValidForChargePredicate, Charge, serviceAccount)); async Task <Result <string> > Charge(Booking booking, ApiCaller serviceAcc) { if (BookingStatusesNeededRefreshBeforePayment.Contains(booking.Status)) { var(_, isRefreshingFailure, refreshingError) = await _supplierBookingManagementService.RefreshStatus(booking, serviceAcc, BookingChangeEvents.Charge); if (isRefreshingFailure) { await _bookingRecordsUpdater.ChangeStatus(booking, BookingStatuses.ManualCorrectionNeeded, _dateTimeProvider.UtcNow(), serviceAcc, new BookingChangeReason { Source = BookingChangeSources.System, Event = BookingChangeEvents.Charge, Reason = "Failure in refreshing booking status before payment" }); return(Result.Failure <string>(refreshingError)); } // Need to get fresh information about the booking booking = await _context.Bookings.SingleOrDefaultAsync(b => b.ReferenceCode == booking.ReferenceCode); if (BookingStatusesNeededRefreshBeforePayment.Contains(booking.Status)) { await _bookingRecordsUpdater.ChangeStatus(booking, BookingStatuses.ManualCorrectionNeeded, _dateTimeProvider.UtcNow(), serviceAcc, new BookingChangeReason { Source = BookingChangeSources.System, Event = BookingChangeEvents.Charge, Reason = "After refreshing the booking received a status requiring refreshing" }); return(Result.Failure <string>($"Booking {booking.ReferenceCode} with status {booking.Status} cannot be charged")); } } var chargeResult = await _accountPaymentService.Charge(booking, serviceAccount.ToApiCaller()); if (chargeResult.IsFailure) { var(_, isCancelFailure, error) = await _supplierBookingManagementService.Cancel(booking, serviceAccount.ToApiCaller(), BookingChangeEvents.Charge); if (isCancelFailure) { await _bookingRecordsUpdater.ChangeStatus(booking, BookingStatuses.ManualCorrectionNeeded, _dateTimeProvider.UtcNow(), serviceAcc, new BookingChangeReason { Source = BookingChangeSources.System, Event = BookingChangeEvents.Charge, Reason = "It is impossible to cancel the booking for which the error occurred during charge" }); return(Result.Failure <string>(error)); } } return(chargeResult); } }
private async Task <Result <BatchOperationResult> > ExecuteBatchAction(List <int> bookingIds, Expression <Func <Booking, bool> > predicate, Func <Booking, ApiCaller, Task <Result <string> > > action, ServiceAccount serviceAccount) { var bookings = await GetBookings(); return(await ValidateCount() .Map(ProcessBookings)); Task <List <Booking> > GetBookings() => _context.Bookings .Where(booking => bookingIds.Contains(booking.Id)) .Where(predicate) .ToListAsync(); Result ValidateCount() => bookings.Count != bookingIds.Count ? Result.Failure("Invalid booking ids. Could not find some of requested bookings.") : Result.Success(); Task <BatchOperationResult> ProcessBookings() => Combine(bookings.Select(booking => action(booking, serviceAccount.ToApiCaller()))); async Task <BatchOperationResult> Combine(IEnumerable <Task <Result <string> > > results) { var builder = new StringBuilder(); bool hasErrors = false; foreach (var result in results) { var(_, isFailure, value, error) = await result; if (isFailure) { hasErrors = true; } builder.AppendLine(isFailure ? error : value); } return(new BatchOperationResult(builder.ToString(), hasErrors)); } }