コード例 #1
0
        public async Task <RefundResult> ExecuteAsync(string merchantId, string paymentRequestId,
                                                      string destinationWalletAddress)
        {
            IPaymentRequest paymentRequest =
                await _paymentRequestService.GetAsync(merchantId, paymentRequestId);

            if (paymentRequest == null)
            {
                throw new RefundValidationException(RefundErrorType.PaymentRequestNotFound);
            }

            if (!paymentRequest.StatusValidForRefund())
            {
                throw new RefundValidationException(RefundErrorType.NotAllowedInStatus);
            }

            IEnumerable <IPaymentRequestTransaction> paymentTxs =
                (await _transactionsService.GetByWalletAsync(paymentRequest.WalletAddress)).Where(x => x.IsPayment()).ToList();

            if (!paymentTxs.Any())
            {
                throw new RefundValidationException(RefundErrorType.NoPaymentTransactions);
            }

            if (paymentTxs.MoreThanOne())
            {
                throw new RefundValidationException(RefundErrorType.MultitransactionNotSupported);
            }

            IPaymentRequestTransaction tx = paymentTxs.Single();

            bool isValidAddress = string.IsNullOrWhiteSpace(destinationWalletAddress) ||
                                  await _blockchainAddressValidator.Execute(destinationWalletAddress, tx.Blockchain);

            if (!isValidAddress)
            {
                throw new RefundValidationException(RefundErrorType.InvalidDestinationAddress);
            }

            if (!tx.SourceWalletAddresses.Any())
            {
                throw new RefundValidationException(RefundErrorType.InvalidDestinationAddress);
            }

            if (string.IsNullOrWhiteSpace(destinationWalletAddress))
            {
                if (tx.SourceWalletAddresses.MoreThanOne())
                {
                    throw new RefundValidationException(RefundErrorType.InvalidDestinationAddress);
                }
            }

            //validation finished, refund request accepted
            await _paymentRequestService.UpdateStatusAsync(paymentRequest.WalletAddress,
                                                           PaymentRequestStatusInfo.RefundInProgress());

            TransferResult transferResult;

            DateTime refundDueDate;

            try
            {
                TransferCommand refundTransferCommand = Mapper.Map <TransferCommand>(tx,
                                                                                     opts => opts.Items["destinationAddress"] = destinationWalletAddress);

                transferResult = await _transferService.ExecuteAsync(refundTransferCommand);

                refundDueDate = transferResult.Timestamp.Add(_refundExpirationPeriod);

                foreach (var transferResultTransaction in transferResult.Transactions)
                {
                    if (!string.IsNullOrEmpty(transferResultTransaction.Error))
                    {
                        await _log.WriteWarningAsync(nameof(RefundService), nameof(ExecuteAsync),
                                                     transferResultTransaction.ToJson(), "Transaction failed");

                        continue;
                    }

                    IPaymentRequestTransaction refundTransaction = await _transactionsService.CreateTransactionAsync(
                        new CreateTransactionCommand
                    {
                        Amount        = transferResultTransaction.Amount,
                        AssetId       = transferResultTransaction.AssetId,
                        Confirmations = 0,
                        Hash          = transferResultTransaction.Hash,
                        WalletAddress = paymentRequest.WalletAddress,
                        Type          = TransactionType.Refund,
                        Blockchain    = transferResult.Blockchain,
                        FirstSeen     = null,
                        DueDate       = refundDueDate,
                        TransferId    = transferResult.Id,
                        IdentityType  = transferResultTransaction.IdentityType,
                        Identity      = transferResultTransaction.Identity
                    });

                    await _transactionPublisher.PublishAsync(refundTransaction);
                }

                if (transferResult.Transactions.All(x => x.HasError))
                {
                    throw new RefundOperationFailedException {
                              TransferErrors = transferResult.Transactions.Select(x => x.Error)
                    }
                }
                ;

                IEnumerable <TransferTransactionResult> errorTransactions =
                    transferResult.Transactions.Where(x => x.HasError).ToList();

                if (errorTransactions.Any())
                {
                    throw new RefundOperationPartiallyFailedException(errorTransactions.Select(x => x.Error));
                }
            }
            catch (Exception)
            {
                await _paymentRequestService.UpdateStatusAsync(paymentRequest.WalletAddress,
                                                               PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.UnknownRefund));

                throw;
            }

            return(await PrepareRefundResult(paymentRequest, transferResult, refundDueDate));
        }