/// <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 _storage.DoesPaymentExistAsync(invoice.TrackingNumber, cancellationToken).ConfigureAwaitFalse()) { _logger.LogInformation(LoggingEvents.RequestPayment, _options.Messages.DuplicateTrackingNumber); return(new PaymentRequestResult { TrackingNumber = invoice.TrackingNumber, Status = PaymentRequestResultStatus.TrackingNumberAlreadyExists, Message = _options.Messages.DuplicateTrackingNumber, GatewayTransporter = new NullGatewayTransporter() }); } // Create a payment token var paymentToken = await _tokenProvider .ProvideTokenAsync(invoice, cancellationToken) .ConfigureAwaitFalse(); if (paymentToken.IsNullOrEmpty()) { throw new PaymentTokenProviderException($"The Payment Token Provider '{_tokenProvider.GetType().Name}' didn't provide any token."); } // Check the created payment token if (await _storage.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 _storage.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 _storage.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 _storage.CreateTransactionAsync(newTransaction, cancellationToken).ConfigureAwaitFalse(); _logger.LogInformation(LoggingEvents.RequestPayment, $"Requesting the invoice {invoice.TrackingNumber} is finished."); return(requestResult); }
/// <inheritdoc /> public virtual async Task <IPaymentVerifyResult> VerifyAsync(long trackingNumber, CancellationToken cancellationToken = default) { _logger.LogInformation(LoggingEvents.VerifyPayment, $"Verifying the invoice {trackingNumber} is started."); var payment = await _storage .GetPaymentByTrackingNumberAsync(trackingNumber, cancellationToken) .ConfigureAwaitFalse(); if (payment == null) { _logger.LogError(LoggingEvents.VerifyPayment, $"Verifying the invoice {trackingNumber} is failed. The operation is not valid. No payment found with the tracking number {trackingNumber}"); throw new InvoiceNotFoundException(trackingNumber); } if (payment.IsCompleted) { _logger.LogInformation(LoggingEvents.VerifyPayment, $"Verifying the invoice {trackingNumber} is finished. The requested payment is already processed before."); return(new PaymentVerifyResult { TrackingNumber = payment.TrackingNumber, Amount = payment.Amount, GatewayName = payment.GatewayName, GatewayAccountName = payment.GatewayAccountName, TransactionCode = payment.TransactionCode, Status = payment.IsPaid ? PaymentVerifyResultStatus.AlreadyVerified : PaymentVerifyResultStatus.Failed, Message = _options.Messages.PaymentIsAlreadyProcessedBefore }); } var gateway = _gatewayProvider.Provide(payment.GatewayName); var transactions = await _storage.GetTransactionsAsync(payment.Id, cancellationToken).ConfigureAwaitFalse(); var invoiceContext = new InvoiceContext(payment, transactions); PaymentVerifyResult verifyResult; try { verifyResult = await gateway .VerifyAsync(invoiceContext, cancellationToken) .ConfigureAwaitFalse() as PaymentVerifyResult; } catch (Exception exception) { _logger.LogError(LoggingEvents.VerifyPayment, exception, $"Verifying the invoice {trackingNumber} is finished. An error occurred during requesting."); throw; } if (verifyResult == null) { throw new Exception($"The {gateway.GetCompleteGatewayName()} returns null instead of a result."); } verifyResult.TrackingNumber = payment.TrackingNumber; verifyResult.Amount = payment.Amount; verifyResult.GatewayName = payment.GatewayName; verifyResult.GatewayAccountName = payment.GatewayAccountName; payment.IsCompleted = true; payment.IsPaid = verifyResult.IsSucceed; payment.TransactionCode = verifyResult.TransactionCode; await _storage.UpdatePaymentAsync(payment, cancellationToken).ConfigureAwaitFalse(); var transaction = new Transaction { Amount = verifyResult.Amount, IsSucceed = verifyResult.IsSucceed, Message = verifyResult.Message, Type = TransactionType.Verify, AdditionalData = AdditionalDataConverter.ToJson(verifyResult), PaymentId = payment.Id }; await _storage.CreateTransactionAsync(transaction, cancellationToken).ConfigureAwaitFalse(); _logger.LogInformation(LoggingEvents.VerifyPayment, $"Verifying the invoice {trackingNumber} is finished."); return(verifyResult); }
/// <inheritdoc /> public virtual async Task <IPaymentRefundResult> RefundAsync(RefundInvoice invoice, CancellationToken cancellationToken = default) { if (invoice == null) { throw new ArgumentNullException(nameof(invoice)); } _logger.LogInformation(LoggingEvents.RefundPayment, $"Refunding the invoice {invoice.TrackingNumber} is started."); var payment = await _storage.GetPaymentByTrackingNumberAsync(invoice.TrackingNumber, cancellationToken).ConfigureAwaitFalse(); if (payment == null) { _logger.LogError(LoggingEvents.RefundPayment, $"Refunding the invoice {invoice.TrackingNumber} is failed. The operation is not valid. No payment found with the tracking number {invoice.TrackingNumber}"); throw new InvoiceNotFoundException(invoice.TrackingNumber); } if (!payment.IsCompleted) { var message = $"{_options.Messages.OnlyCompletedPaymentCanBeRefunded} Tracking number: {invoice.TrackingNumber}."; _logger.LogInformation(LoggingEvents.RefundPayment, $"Refunding the invoice {invoice.TrackingNumber} is finished. {message}"); return(PaymentRefundResult.Failed(message)); } Money amountToRefund; if (invoice.Amount == 0) { amountToRefund = payment.Amount; } else if (invoice.Amount > payment.Amount) { throw new Exception("Amount cannot be greater than the amount of the paid payment."); } else { amountToRefund = invoice.Amount; } var gateway = _gatewayProvider.Provide(payment.GatewayName); var transactions = await _storage.GetTransactionsAsync(payment.Id, cancellationToken).ConfigureAwaitFalse(); var verifyContext = new InvoiceContext(payment, transactions); PaymentRefundResult refundResult; try { refundResult = await gateway .RefundAsync(verifyContext, amountToRefund, cancellationToken) .ConfigureAwaitFalse() as PaymentRefundResult; } catch (Exception exception) { _logger.LogError(exception, "Parbad exception. An error occurred during requesting."); throw; } if (refundResult == null) { throw new Exception($"Gateway {gateway.GetCompleteGatewayName()} returns null instead of a result."); } refundResult.TrackingNumber = payment.TrackingNumber; refundResult.Amount = amountToRefund; refundResult.GatewayName = payment.GatewayName; refundResult.GatewayAccountName = payment.GatewayAccountName; var newtTransaction = new Transaction { Amount = refundResult.Amount, Type = TransactionType.Refund, IsSucceed = refundResult.IsSucceed, Message = refundResult.Message, AdditionalData = AdditionalDataConverter.ToJson(refundResult), PaymentId = payment.Id }; await _storage.CreateTransactionAsync(newtTransaction, cancellationToken).ConfigureAwaitFalse(); _logger.LogInformation(LoggingEvents.RefundPayment, $"Refunding the invoice {invoice.TrackingNumber} is finished."); return(refundResult); }
/// <inheritdoc /> public virtual async Task <IPaymentRequestResult> RequestAsync(Invoice invoice, CancellationToken cancellationToken = default) { if (invoice == null) { throw new ArgumentNullException(nameof(invoice)); } _logger.LogInformation(LoggingEvents.RequestPayment, $"New payment request with the tracking number {invoice.TrackingNumber} is started." + $"{nameof(invoice.Amount)}:{invoice.Amount}" + $"GatewayName:{GatewayHelper.GetNameByType(invoice.GatewayType)}"); // Check the tracking number if (await _database.Payments .AnyAsync(model => model.TrackingNumber == 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() }); } // Check the payment token var paymentToken = await _tokenProvider .ProvideTokenAsync(invoice, cancellationToken) .ConfigureAwaitFalse(); if (await _database.Payments .AnyAsync(model => model.Token == paymentToken, cancellationToken) .ConfigureAwaitFalse()) { var message = $"The payment token \"{paymentToken}\" already exists."; _logger.LogError(LoggingEvents.RequestPayment, message); throw new PaymentTokenProviderException(message); } var gateway = _gatewayProvider.Provide(invoice.GatewayType); // Add database var newPayment = new Payment { TrackingNumber = invoice.TrackingNumber, Amount = invoice.Amount, IsCompleted = false, IsPaid = false, Token = paymentToken, GatewayName = gateway.GetName(), CreatedOn = DateTime.UtcNow }; _database.Payments.Add(newPayment); if (await _database.SaveChangesAsync(cancellationToken).ConfigureAwaitFalse() == 0) { _logger.LogError(LoggingEvents.RequestPayment, "Nothing is saved into the database."); throw new DatabaseSaveRecordException(); } _logger.LogInformation(LoggingEvents.RequestPayment, $"The payment with tracking number {invoice.TrackingNumber} is about to processing." + $"{nameof(invoice.Amount)}:{invoice.Amount}" + $"GatewayName:{GatewayHelper.GetNameByType(invoice.GatewayType)}"); PaymentRequestResult requestResult; try { requestResult = await gateway .RequestAsync(invoice, cancellationToken) .ConfigureAwaitFalse() as PaymentRequestResult; if (requestResult == null) { throw new Exception($"Gateway {gateway.GetName()} returns null instead of a result."); } } catch (Exception exception) { string exceptionMessage; if (exception is OptionsValidationException) { exceptionMessage = $"Gateway {gateway.GetName()} is not configured or has some validation errors."; } else { exceptionMessage = exception.Message; } _logger.LogError(exception, exceptionMessage); newPayment.IsCompleted = true; newPayment.IsPaid = false; newPayment.UpdatedOn = DateTime.UtcNow; requestResult = PaymentRequestResult.Failed(exceptionMessage); } requestResult.TrackingNumber = invoice.TrackingNumber; requestResult.Amount = invoice.Amount; requestResult.GatewayName = gateway.GetName(); newPayment.Transactions.Add(new Transaction { Amount = invoice.Amount, Type = TransactionType.Request, IsSucceed = requestResult.IsSucceed, Message = requestResult.Message, AdditionalData = AdditionalDataConverter.ToJson(requestResult), CreatedOn = DateTime.UtcNow }); if (await _database.SaveChangesAsync(cancellationToken).ConfigureAwaitFalse() == 0) { _logger.LogError(LoggingEvents.RequestPayment, "Nothing is saved into database."); throw new DatabaseSaveRecordException(); } return(requestResult); }
/// <inheritdoc /> public virtual async Task <IPaymentRefundResult> RefundAsync(RefundInvoice invoice, CancellationToken cancellationToken = default) { if (invoice == null) { throw new ArgumentNullException(nameof(invoice)); } _logger.LogInformation(LoggingEvents.RefundPayment, $"Refund starts for the payment with tracking number {invoice.TrackingNumber}."); var payment = await _database.Payments .Include(model => model.Transactions) .SingleOrDefaultAsync(model => model.TrackingNumber == invoice.TrackingNumber, cancellationToken) .ConfigureAwaitFalse(); if (payment == null) { var message = $"The operation is not valid. No payment found with the tracking number {invoice.TrackingNumber}."; _logger.LogError(LoggingEvents.RefundPayment, message); return(PaymentRefundResult.Failed(message)); } if (!payment.IsCompleted) { var message = $"The payment with the tracking number {invoice.TrackingNumber} is not completed yet. Only a completed payment can be refund."; _logger.LogError(LoggingEvents.RefundPayment, message); return(PaymentRefundResult.Failed(message)); } Money amountToRefund; if (invoice.Amount == 0) { amountToRefund = payment.Amount; } else if (invoice.Amount > payment.Amount) { throw new Exception("Amount cannot be greater than the amount of the paid payment."); } else { amountToRefund = payment.Amount; } var gateway = _gatewayProvider.Provide(payment.GatewayName); PaymentRefundResult refundResult; try { refundResult = await gateway .RefundAsync(payment, amountToRefund, cancellationToken) .ConfigureAwaitFalse() as PaymentRefundResult; } catch (OptionsValidationException) { throw new GatewayOptionsConfigurationException(gateway.GetName()); } catch (Exception exception) { _logger.LogError(exception, "Parbad exception. An error occurred during requesting."); throw; } if (refundResult == null) { throw new Exception($"Gateway {gateway.GetName()} returns null instead of a result."); } refundResult.TrackingNumber = payment.TrackingNumber; refundResult.Amount = amountToRefund; refundResult.GatewayName = payment.GatewayName; payment.Transactions.Add(new Transaction { Amount = refundResult.Amount, Type = TransactionType.Refund, IsSucceed = refundResult.IsSucceed, Message = refundResult.Message, AdditionalData = AdditionalDataConverter.ToJson(refundResult), CreatedOn = DateTime.UtcNow }); if (await _database.SaveChangesAsync(cancellationToken).ConfigureAwaitFalse() == 0) { _logger.LogError(LoggingEvents.RefundPayment, "Refund ends. Nothing is saved into database."); throw new DatabaseSaveRecordException(); } _logger.LogInformation(LoggingEvents.RefundPayment, "Refund ends."); return(refundResult); }
/// <inheritdoc /> public virtual async Task <IPaymentVerifyResult> VerifyAsync(Action <IPaymentVerifyingContext> context, CancellationToken cancellationToken = default) { _logger.LogError(LoggingEvents.VerifyPayment, "Verify Starts."); var paymentToken = await _tokenProvider.RetrieveTokenAsync(cancellationToken).ConfigureAwaitFalse(); if (string.IsNullOrEmpty(paymentToken)) { _logger.LogError(LoggingEvents.VerifyPayment, "Verify Ends. No Payment Token is received."); throw new PaymentTokenProviderException("No Token is received."); } var payment = await _database.Payments .Include(model => model.Transactions) .SingleOrDefaultAsync(model => model.Token == paymentToken, cancellationToken) .ConfigureAwaitFalse(); if (payment == null) { _logger.LogError(LoggingEvents.VerifyPayment, $"Verify Ends. The operation is not valid. No payment found with the token: {paymentToken}"); return(new PaymentVerifyResult { IsSucceed = false, Message = "The operation is not valid. No payment found with the given token." }); } if (payment.IsCompleted) { _logger.LogError(LoggingEvents.VerifyPayment, $"Verify Ends. Tracking Number {payment.TrackingNumber}. Result: The requested payment is already processed before."); return(new PaymentVerifyResult { TrackingNumber = payment.TrackingNumber, Amount = payment.Amount, GatewayName = payment.GatewayName, TransactionCode = payment.TransactionCode, IsSucceed = false, Message = "The requested payment is already processed before." }); } var c = new PaymentVerifyingContext { TrackingNumber = payment.TrackingNumber, GatewayName = payment.GatewayName }; context(c); if (c.IsCancelled) { var message = c.CancellationReason ?? Resources.PaymentCanceledProgrammatically; _logger.LogInformation(LoggingEvents.VerifyPayment, message); payment.IsCompleted = true; payment.IsPaid = false; payment.UpdatedOn = DateTime.UtcNow; payment.Transactions.Add(new Transaction { Amount = payment.Amount, IsSucceed = false, Message = message, Type = TransactionType.Verify, CreatedOn = DateTime.UtcNow }); if (await _database.SaveChangesAsync(cancellationToken).ConfigureAwaitFalse() == 0) { _logger.LogError(LoggingEvents.VerifyPayment, "Nothing is saved into database."); throw new DatabaseSaveRecordException(); } return(new PaymentVerifyResult { TrackingNumber = payment.TrackingNumber, Amount = payment.Amount, IsSucceed = false, GatewayName = payment.GatewayName, Message = message }); } var gateway = _gatewayProvider.Provide(payment.GatewayName); _logger.LogInformation(LoggingEvents.VerifyPayment, $"The payment with the tracking Number {payment.TrackingNumber} is about to verifying."); PaymentVerifyResult verifyResult; try { verifyResult = await gateway .VerifyAsync(payment, cancellationToken) .ConfigureAwaitFalse() as PaymentVerifyResult; } catch (OptionsValidationException) { throw new GatewayOptionsConfigurationException(gateway.GetName()); } catch (Exception exception) { _logger.LogError(exception, "Parbad exception. An error occurred during requesting."); throw; } if (verifyResult == null) { throw new Exception($"Gateway {gateway.GetName()} returns null instead of a result."); } verifyResult.TrackingNumber = payment.TrackingNumber; verifyResult.Amount = payment.Amount; verifyResult.GatewayName = payment.GatewayName; _logger.LogInformation(LoggingEvents.VerifyPayment, "Verifying finished. " + $"Tracking Number {payment.TrackingNumber}. " + $"IsSucceed: {verifyResult.IsSucceed}" + $"Message: {verifyResult.Message}" + $"GatewayName: {verifyResult.GatewayName}"); payment.IsCompleted = true; payment.IsPaid = verifyResult.IsSucceed; payment.TransactionCode = verifyResult.TransactionCode; payment.UpdatedOn = DateTime.UtcNow; payment.Transactions.Add(new Transaction { Amount = verifyResult.Amount, IsSucceed = verifyResult.IsSucceed, Message = verifyResult.Message, Type = TransactionType.Verify, AdditionalData = AdditionalDataConverter.ToJson(verifyResult), CreatedOn = DateTime.UtcNow }); if (await _database.SaveChangesAsync(cancellationToken).ConfigureAwaitFalse() == 0) { _logger.LogError(LoggingEvents.VerifyPayment, "Nothing is saved into database."); throw new DatabaseSaveRecordException(); } _logger.LogInformation(LoggingEvents.VerifyPayment, "Verify ends."); return(verifyResult); }
/// <inheritdoc /> public virtual async Task <IPaymentVerifyResult> VerifyAsync(Action <IPaymentVerifyingContext> context, CancellationToken cancellationToken = default) { _logger.LogInformation(LoggingEvents.VerifyPayment, "Verifying the invoice is started."); var paymentToken = await _tokenProvider.RetrieveTokenAsync(cancellationToken).ConfigureAwaitFalse(); if (string.IsNullOrEmpty(paymentToken)) { _logger.LogError(LoggingEvents.VerifyPayment, "Verify Ends. No Payment Token is received."); throw new PaymentTokenProviderException("No Token is received."); } var payment = await _storageManager.GetPaymentByTokenAsync(paymentToken, cancellationToken).ConfigureAwaitFalse(); if (payment == null) { _logger.LogError(LoggingEvents.VerifyPayment, $"Verify Ends. The operation is not valid. No payment found with the token: {paymentToken}"); return(new PaymentVerifyResult { IsSucceed = false, Message = "The operation is not valid. No payment found with the given token." }); } if (payment.IsCompleted) { _logger.LogError(LoggingEvents.VerifyPayment, $"Verify Ends. Tracking Number {payment.TrackingNumber}. Result: The requested payment is already processed before."); return(new PaymentVerifyResult { TrackingNumber = payment.TrackingNumber, Amount = payment.Amount, GatewayName = payment.GatewayName, GatewayAccountName = payment.GatewayAccountName, TransactionCode = payment.TransactionCode, IsSucceed = false, Message = "The requested payment is already processed before." }); } var c = new PaymentVerifyingContext { TrackingNumber = payment.TrackingNumber, GatewayName = payment.GatewayName }; context(c); if (c.IsCancelled) { var message = c.CancellationReason ?? Resources.PaymentCanceledProgrammatically; _logger.LogInformation(LoggingEvents.VerifyPayment, message); payment.IsCompleted = true; payment.IsPaid = false; await _storageManager.UpdatePaymentAsync(payment, cancellationToken).ConfigureAwaitFalse(); var newTransaction = new Transaction { Amount = payment.Amount, IsSucceed = false, Message = message, Type = TransactionType.Verify, PaymentId = payment.Id }; await _storageManager.CreateTransactionAsync(newTransaction, cancellationToken).ConfigureAwaitFalse(); return(new PaymentVerifyResult { TrackingNumber = payment.TrackingNumber, Amount = payment.Amount, IsSucceed = false, GatewayName = payment.GatewayName, GatewayAccountName = payment.GatewayAccountName, Message = message }); } var gateway = _gatewayProvider.Provide(payment.GatewayName); var transactions = await _storageManager.GetTransactionsAsync(payment, cancellationToken).ConfigureAwaitFalse(); var verifyContext = new InvoiceContext(payment, transactions); _logger.LogInformation(LoggingEvents.VerifyPayment, $"The payment with the tracking Number {payment.TrackingNumber} is about to verifying."); PaymentVerifyResult verifyResult; try { verifyResult = await gateway .VerifyAsync(verifyContext, cancellationToken) .ConfigureAwaitFalse() as PaymentVerifyResult; } catch (Exception exception) { _logger.LogError(exception, "Parbad exception. An error occurred during requesting."); throw; } if (verifyResult == null) { throw new Exception($"The gateway {gateway.GetCompleteGatewayName()} returns null instead of a result."); } verifyResult.TrackingNumber = payment.TrackingNumber; verifyResult.Amount = payment.Amount; verifyResult.GatewayName = payment.GatewayName; verifyResult.GatewayAccountName = payment.GatewayAccountName; _logger.LogInformation(LoggingEvents.VerifyPayment, "Verifying finished. " + $"Tracking Number {payment.TrackingNumber}. " + $"IsSucceed: {verifyResult.IsSucceed}" + $"Message: {verifyResult.Message}" + $"GatewayName: {verifyResult.GatewayName}"); payment.IsCompleted = true; payment.IsPaid = verifyResult.IsSucceed; payment.TransactionCode = verifyResult.TransactionCode; await _storageManager.UpdatePaymentAsync(payment, cancellationToken).ConfigureAwaitFalse(); var transaction = new Transaction { Amount = verifyResult.Amount, IsSucceed = verifyResult.IsSucceed, Message = verifyResult.Message, Type = TransactionType.Verify, AdditionalData = AdditionalDataConverter.ToJson(verifyResult), PaymentId = payment.Id }; await _storageManager.CreateTransactionAsync(transaction, cancellationToken).ConfigureAwaitFalse(); _logger.LogInformation(LoggingEvents.VerifyPayment, "Verify ends."); return(verifyResult); }
/// <inheritdoc /> public virtual async Task <IPaymentRequestResult> RequestAsync(Invoice invoice, CancellationToken cancellationToken = default) { if (invoice == null) { throw new ArgumentNullException(nameof(invoice)); } _logger.LogInformation(LoggingEvents.RequestPayment, $"New payment request with the tracking number {invoice.TrackingNumber} is started." + $"{nameof(invoice.Amount)}:{invoice.Amount}" + $"GatewayName:{GatewayHelper.GetNameByType(invoice.GatewayType)}"); // 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 = $"The payment token \"{paymentToken}\" already exists."; _logger.LogError(LoggingEvents.RequestPayment, message); throw new PaymentTokenProviderException(message); } var gateway = _gatewayProvider.Provide(invoice.GatewayType); var newPayment = new Payment { TrackingNumber = invoice.TrackingNumber, Amount = invoice.Amount, IsCompleted = false, IsPaid = false, Token = paymentToken, GatewayName = gateway.GetName() }; await _storageManager.CreatePaymentAsync(newPayment, cancellationToken).ConfigureAwaitFalse(); _logger.LogInformation(LoggingEvents.RequestPayment, $"The payment with tracking number {invoice.TrackingNumber} is about to processing." + $"{nameof(invoice.Amount)}:{invoice.Amount}" + $"GatewayName:{GatewayHelper.GetNameByType(invoice.GatewayType)}"); PaymentRequestResult requestResult; try { requestResult = await gateway .RequestAsync(invoice, cancellationToken) .ConfigureAwaitFalse() as PaymentRequestResult; if (requestResult == null) { throw new Exception($"Gateway {gateway.GetName()} 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.GetName(); 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(); return(requestResult); }