Example #1
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);
        }
Example #2
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);
        }