public async Task Transfer(string sourceWalletJmbg, string sourceWalletPass, decimal amount, string destinationWalletJmbg) { if (string.IsNullOrEmpty(sourceWalletJmbg)) { throw new ArgumentNullException($"{nameof(sourceWalletJmbg)}"); } if (string.IsNullOrEmpty(sourceWalletPass)) { throw new ArgumentNullException($"{nameof(sourceWalletPass)}"); } if (string.IsNullOrEmpty(destinationWalletJmbg)) { throw new ArgumentNullException($"{nameof(destinationWalletJmbg)}"); } if (amount < 0) { throw new InvalidOperationException("Amount must be greater than 0"); } Wallet sourceWallet = await CoreUnitOfWork.WalletRepository.GetFirstOrDefaultWithIncludes( w => w.JMBG == sourceWalletJmbg, w => w.Transactions ); if (sourceWallet == null) { throw new InvalidOperationException($"{nameof(Wallet)} with JMBG = {sourceWallet} doesn't exist"); } if (!sourceWallet.IsPassValid(sourceWalletPass)) { throw new InvalidOperationException($"Invalid password."); } if (sourceWallet.IsBlocked) { throw new InvalidOperationException($"{nameof(Transfer)} from blocked wallet #{sourceWallet.JMBG} is forbidden"); } Wallet destinationWallet = await CoreUnitOfWork.WalletRepository.GetFirstOrDefaultWithIncludes( w => w.JMBG == destinationWalletJmbg, w => w.Transactions ); if (destinationWallet == null) { throw new InvalidOperationException($"{nameof(Wallet)} with JMBG = {sourceWalletJmbg} doesn't exist"); } if (destinationWallet.IsBlocked) { throw new InvalidOperationException($"{nameof(Transfer)} to blocked wallet #{destinationWallet.JMBG} is forbidden"); } decimal transferFee = await FeeService.CalculateTransferFee( sourceWallet, amount, DaysAfterWalletCreationWithNoFee, IsFirstTransferFreeInMonth, FixedFee, PercentageFee, FeeLimit); await CoreUnitOfWork.BeginTransactionAsync(); try { sourceWallet.PayOut(amount, TransactionType.TransferPayOut, MaxWithdraw); if (transferFee > 0) { sourceWallet.PayOut(transferFee, TransactionType.FeePayOut, MaxWithdraw); await CoreUnitOfWork.WalletRepository.Update(sourceWallet); await CoreUnitOfWork.SaveChangesAsync(); } destinationWallet.PayIn(amount, TransactionType.TransferPayIn, MaxDeposit); await CoreUnitOfWork.WalletRepository.Update(sourceWallet); await CoreUnitOfWork.SaveChangesAsync(); await CoreUnitOfWork.WalletRepository.Update(destinationWallet); await CoreUnitOfWork.SaveChangesAsync(); await CoreUnitOfWork.CommitTransactionAsync(); } catch (InvalidOperationException ex) { await CoreUnitOfWork.RollbackTransactionAsync(); throw ex; } }