private async Task <PaymentRequestStatusInfo> GetStatusForPayment(IPaymentRequest paymentRequest) { IReadOnlyList <IPaymentRequestTransaction> txs = (await _transactionsService.GetByWalletAsync(paymentRequest.WalletAddress)).Where(x => x.IsPayment()).ToList(); if (!txs.Any()) { return((paymentRequest.DueDate < DateTime.UtcNow) ? PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.PaymentExpired) : PaymentRequestStatusInfo.New()); } decimal btcPaid; var assetId = txs.GetAssetId(); switch (assetId) { case LykkeConstants.SatoshiAsset: btcPaid = txs.GetTotal().SatoshiToBtc(); break; default: btcPaid = txs.GetTotal(); break; } bool allConfirmed = txs.All(x => x.Confirmed(_transactionConfirmationCount)); var paidDate = txs.GetLatestDate(); if (paidDate > paymentRequest.DueDate) { if (allConfirmed) { return(PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.LatePaid, btcPaid, paidDate)); } return(paymentRequest.GetCurrentStatusInfo()); } IOrder actualOrder = await _orderService.GetActualAsync(paymentRequest.Id, paidDate) ?? await _orderService.GetLatestOrCreateAsync(paymentRequest); if (!allConfirmed) { return(PaymentRequestStatusInfo.InProcess()); } decimal btcToBePaid = actualOrder.PaymentAmount; var fulfillment = await _calculationService.CalculateBtcAmountFullfillmentAsync(btcToBePaid, btcPaid); switch (fulfillment) { case AmountFullFillmentStatus.Below: return(PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.PaymentAmountBelow, btcPaid, paidDate)); case AmountFullFillmentStatus.Exact: return(PaymentRequestStatusInfo.Confirmed(btcPaid, paidDate)); case AmountFullFillmentStatus.Above: return(PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.PaymentAmountAbove, btcPaid, paidDate)); default: throw new Exception("Unexpected amount fullfillment status"); } }
public async Task <PaymentResult> PayAsync(PaymentCommand cmd) { IPaymentRequest paymentRequest = await _paymentRequestRepository.GetAsync(cmd.MerchantId, cmd.PaymentRequestId); if (paymentRequest == null) { throw new PaymentRequestNotFoundException(cmd.MerchantId, cmd.PaymentRequestId); } string payerWalletAddress = (await _merchantWalletService.GetDefaultAsync( cmd.PayerMerchantId, paymentRequest.PaymentAssetId, PaymentDirection.Outgoing)).WalletAddress; string destinationWalletAddress = await _walletsManager.ResolveBlockchainAddressAsync( paymentRequest.WalletAddress, paymentRequest.PaymentAssetId); bool locked = await _paymentLocksService.TryAcquireLockAsync( paymentRequest.Id, cmd.MerchantId, paymentRequest.DueDate); if (!locked) { throw new DistributedLockAcquireException(paymentRequest.Id); } TransferResult transferResult; try { await UpdateStatusAsync(paymentRequest.WalletAddress, PaymentRequestStatusInfo.InProcess()); transferResult = await _paymentRetryPolicy .ExecuteAsync(() => _transferService.PayThrowFail( paymentRequest.PaymentAssetId, payerWalletAddress, destinationWalletAddress, cmd.Amount)); foreach (var transferResultTransaction in transferResult.Transactions) { IPaymentRequestTransaction paymentTx = await _transactionsService.CreateTransactionAsync( new CreateTransactionCommand { Amount = transferResultTransaction.Amount, Blockchain = transferResult.Blockchain, AssetId = transferResultTransaction.AssetId, WalletAddress = paymentRequest.WalletAddress, DueDate = paymentRequest.DueDate, IdentityType = transferResultTransaction.IdentityType, Identity = transferResultTransaction.Identity, Confirmations = 0, Hash = transferResultTransaction.Hash, TransferId = transferResult.Id, Type = TransactionType.Payment, SourceWalletAddresses = transferResultTransaction.Sources.ToArray() }); await _transactionPublisher.PublishAsync(paymentTx); } } catch (Exception e) { PaymentRequestStatusInfo newStatus = e is InsufficientFundsException ? PaymentRequestStatusInfo.New() : PaymentRequestStatusInfo.Error(PaymentRequestProcessingError.UnknownPayment); await UpdateStatusAsync(paymentRequest.WalletAddress, newStatus); await _paymentLocksService.ReleaseLockAsync(paymentRequest.Id, cmd.MerchantId); throw; } return(new PaymentResult { PaymentRequestId = paymentRequest.Id, PaymentRequestWalletAddress = paymentRequest.WalletAddress, AssetId = transferResult.Transactions.Unique(x => x.AssetId).Single(), Amount = transferResult.GetSuccedeedTxs().Sum(x => x.Amount) }); }