Ejemplo n.º 1
0
        public async Task <PaymentRequestStatusInfo> GetStatus(string walletAddress)
        {
            IPaymentRequest paymentRequest = await _paymentRequestRepository.FindAsync(walletAddress);

            if (paymentRequest == null)
            {
                throw new PaymentRequestNotFoundException(walletAddress);
            }

            IReadOnlyList <IPaymentRequestTransaction> txs =
                await _transactionsService.GetByWalletAsync(paymentRequest.WalletAddress);

            PaymentRequestStatusInfo paymentStatusInfo;

            if (txs.Any(x => x.IsSettlement()))
            {
                paymentStatusInfo = await GetStatusForSettlement(paymentRequest);
            }
            else if (txs.Any(x => x.IsRefund()))
            {
                paymentStatusInfo = await GetStatusForRefund(paymentRequest);
            }
            else if (txs.Any(x => x.IsPayment()))
            {
                paymentStatusInfo = await GetStatusForPayment(paymentRequest);
            }
            else
            {
                throw new Exception("Inconsistent paymentRequest status");
            }

            return(paymentStatusInfo);
        }
Ejemplo n.º 2
0
        public async Task <PaymentRequestRefund> GetRefundInfoAsync(string walletAddress)
        {
            IReadOnlyList <IPaymentRequestTransaction> transactions =
                (await _transactionsService.GetByWalletAsync(walletAddress)).Where(x => x.IsRefund()).ToList();

            if (!transactions.Any())
            {
                return(null);
            }

            IEnumerable <string> transferIds = transactions.Unique(x => x.TransferId).ToList();

            if (transferIds.MoreThanOne())
            {
                throw new MultiTransactionRefundNotSupportedException();
            }

            Transfer transfer = await _transferService.GetAsync(transferIds.Single());

            IPaymentRequest paymentRequest = await FindAsync(walletAddress);

            return(new PaymentRequestRefund
            {
                Amount = transfer.Amounts.Sum(x => x.Amount ?? 0),
                Timestamp = transfer.CreatedOn,
                Address = transfer.Amounts.Unique(x => x.Destination).Single(),
                DueDate = transactions.OrderByDescending(x => x.DueDate).First().DueDate ?? paymentRequest.DueDate,
                Transactions = Mapper.Map <IEnumerable <PaymentRequestRefundTransaction> >(transactions)
            });
        }
Ejemplo n.º 3
0
        public async Task <IEnumerable <IWalletState> > GetNotExpiredStateAsync()
        {
            IReadOnlyList <IVirtualWallet> wallets = await _virtualWalletService.GetNotExpiredAsync();

            var transactions = new List <IPaymentRequestTransaction>();

            foreach (IEnumerable <IVirtualWallet> batch in wallets.Batch(BatchPieceSize))
            {
                await Task.WhenAll(batch.Select(x => _transactionsService.GetByWalletAsync(x.Id)
                                                .ContinueWith(t =>
                {
                    lock (transactions)
                    {
                        transactions.AddRange(t.Result);
                    }
                })));
            }

            var walletStateResult = new List <WalletState>();

            foreach (IVirtualWallet virtualWallet in wallets)
            {
                walletStateResult.AddRange(virtualWallet.BlockchainWallets.Select(bcnWallet => new WalletState
                {
                    DueDate      = virtualWallet.DueDate,
                    Address      = bcnWallet.Address,
                    Blockchain   = bcnWallet.Blockchain,
                    Transactions = transactions.Where(t =>
                                                      t.WalletAddress == virtualWallet.Id && t.Blockchain == bcnWallet.Blockchain)
                }));
            }

            return(walletStateResult);
        }
Ejemplo n.º 4
0
        public async Task <TResult> Build <TResult, TOrder, TTransaction, TRefund>(IPaymentRequest paymentRequest,
                                                                                   PaymentRequestRefund refundInfo)
        {
            IOrder order = await _orderService.GetAsync(paymentRequest.Id, paymentRequest.OrderId);

            IReadOnlyList <IPaymentRequestTransaction> transactions =
                await _transactionsService.GetByWalletAsync(paymentRequest.WalletAddress);

            IEnumerable <IPaymentRequestTransaction> paymentTransactions = transactions.Where(x => x.IsPayment());

            dynamic model = Mapper.Map <TResult>(paymentRequest);

            model.Order = Mapper.Map <TOrder>(order);

            model.Transactions = Mapper.Map <List <TTransaction> >(paymentTransactions);

            model.Refund = Mapper.Map <TRefund>(refundInfo);

            return(model);
        }
Ejemplo n.º 5
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));
        }