/// <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 <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); }