예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        /// <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);
        }