/// <inheritdoc /> public virtual async Task <IPaymentRequestResult> RequestAsync(Invoice invoice, CancellationToken cancellationToken = default) { if (invoice == null) { throw new ArgumentNullException(nameof(invoice)); } _logger.LogInformation(LoggingEvents.RequestPayment, $"Requesting the invoice {invoice.TrackingNumber} is started."); // Check the tracking number if (await _storageManager.DoesPaymentExistAsync(invoice.TrackingNumber, cancellationToken).ConfigureAwaitFalse()) { _logger.LogInformation(LoggingEvents.RequestPayment, _messagesOptions.Value.DuplicateTrackingNumber); return(new PaymentRequestResult { TrackingNumber = invoice.TrackingNumber, IsSucceed = false, Message = _messagesOptions.Value.DuplicateTrackingNumber, GatewayTransporter = new NullGatewayTransporter() }); } // Create a payment token var paymentToken = await _tokenProvider .ProvideTokenAsync(invoice, cancellationToken) .ConfigureAwaitFalse(); // Check the created payment token if (await _storageManager.DoesPaymentExistAsync(paymentToken, cancellationToken).ConfigureAwaitFalse()) { var message = $"Requesting the invoice {invoice.TrackingNumber} is finished. The payment token \"{paymentToken}\" already exists."; _logger.LogError(LoggingEvents.RequestPayment, message); throw new PaymentTokenProviderException(message); } var gateway = _gatewayProvider.Provide(invoice.GatewayName); var newPayment = new Payment { TrackingNumber = invoice.TrackingNumber, Amount = invoice.Amount, IsCompleted = false, IsPaid = false, Token = paymentToken, GatewayName = gateway.GetRoutingGatewayName() }; await _storageManager.CreatePaymentAsync(newPayment, cancellationToken).ConfigureAwaitFalse(); PaymentRequestResult requestResult; try { requestResult = await gateway .RequestAsync(invoice, cancellationToken) .ConfigureAwaitFalse() as PaymentRequestResult; if (requestResult == null) { throw new Exception($"Requesting the invoice {invoice.TrackingNumber} is finished. The gateway {gateway.GetCompleteGatewayName()} returns null instead of a result."); } } catch (Exception exception) { _logger.LogError(exception, exception.Message); newPayment.IsCompleted = true; newPayment.IsPaid = false; requestResult = PaymentRequestResult.Failed(exception.Message); } requestResult.TrackingNumber = invoice.TrackingNumber; requestResult.Amount = invoice.Amount; requestResult.GatewayName = gateway.GetRoutingGatewayName(); newPayment.GatewayAccountName = requestResult.GatewayAccountName; await _storageManager.UpdatePaymentAsync(newPayment, cancellationToken).ConfigureAwaitFalse(); var newTransaction = new Transaction { Amount = invoice.Amount, Type = TransactionType.Request, IsSucceed = requestResult.IsSucceed, Message = requestResult.Message, AdditionalData = AdditionalDataConverter.ToJson(requestResult), PaymentId = newPayment.Id }; await _storageManager.CreateTransactionAsync(newTransaction, cancellationToken).ConfigureAwaitFalse(); _logger.LogInformation(LoggingEvents.RequestPayment, $"Requesting the invoice {invoice.TrackingNumber} is finished."); return(requestResult); }