/// <summary> /// Transfers money from the source account to the destination account. /// </summary> /// <param name="sourceAccount">The source account.</param> /// <param name="destAccount">The dest account.</param> /// <param name="amount">The amount to transfer.</param> /// <param name="mode">The conversion mode.</param> /// <param name="description">The description of the transaction.</param> /// <returns> /// The operation. /// </returns> public async Task TransferMoney(IAccount sourceAccount, IAccount destAccount, decimal amount, AmountConversionMode mode, string description) { var oldSourceBalance = sourceAccount.Balance; var oldDestBalance = destAccount.Balance; await _original.TransferMoney(sourceAccount, destAccount, amount, mode, description); _hubContext.All.onBalanceChanged(CreateMessage(sourceAccount, oldSourceBalance, description)); _hubContext.All.onBalanceChanged(CreateMessage(destAccount, oldDestBalance, description)); }
/// <summary> /// Transfers money from the source account to the destination account. /// </summary> /// <param name="sourceAccount">The source account.</param> /// <param name="destAccount">The dest account.</param> /// <param name="amount">The amount to transfer.</param> /// <param name="mode">The conversion mode.</param> /// <param name="description">The description of the transaction.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException"> /// </exception> /// <exception cref="System.ArgumentException">Amount should be greater than 0</exception> /// <exception cref="BankingServiceException">The account does not have enough amount of money</exception> public async Task TransferMoney(IAccount sourceAccount, IAccount destAccount, decimal amount, AmountConversionMode mode, string description) { if (sourceAccount == null) { throw new ArgumentNullException(nameof(sourceAccount)); } if (destAccount == null) { throw new ArgumentNullException(nameof(destAccount)); } if (amount <= 0) { throw new ArgumentException("Amount should be greater than 0", nameof(amount)); } if (sourceAccount.Balance < amount) { throw new BankingServiceException("The account does not have enough amount of money"); } using (var transaction = _databaseContext.DemandTransaction()) { try { // get exchange rates and commissions decimal exhangeRate; decimal commissionPercent; if (string.Equals(sourceAccount.Currency, destAccount.Currency, StringComparison.InvariantCultureIgnoreCase)) { exhangeRate = 1.0m; commissionPercent = 0.0m; } else { exhangeRate = await _exchangeRateService.GetExhangeRateAsync(sourceAccount.Currency, destAccount.Currency); commissionPercent = DefaultCommission; } // calc bank commission and new balances var commission = Math.Round(amount * commissionPercent, 2); // in case of commission, source description should include it string sourceDescription; string destDescription; switch (mode) { case AmountConversionMode.SourceToTarget: // source account is charged to pay the bank commission var sourceAmount = amount; var destAmount = Math.Round(exhangeRate * (amount - commission), 2); sourceAccount.Balance = sourceAccount.Balance - amount; destAccount.Balance = destAccount.Balance + destAmount; sourceDescription = $"{description} Amount {sourceAmount.ToString("N2", CultureInfo.InvariantCulture)} {sourceAccount.Currency}."; destDescription = $"{description} Amount {destAmount.ToString("N2", CultureInfo.InvariantCulture)} {destAccount.Currency}."; if (commission > 0) { sourceDescription += $" Bank commission {commission.ToString("N2", CultureInfo.InvariantCulture)} {sourceAccount.Currency}"; } break; case AmountConversionMode.TargetToSource: // destination account is charged to pay the bank commission sourceAmount = Math.Round(amount / exhangeRate, 2); destAmount = amount - commission; sourceAccount.Balance = sourceAccount.Balance - sourceAmount; destAccount.Balance = destAccount.Balance + destAmount; sourceDescription = $"{description} Amount {sourceAmount.ToString("N2", CultureInfo.InvariantCulture)} {sourceAccount.Currency}."; destDescription = $"{description} Amount {destAmount.ToString("N2", CultureInfo.InvariantCulture)} {destAccount.Currency}."; if (commission > 0) { destDescription += $" Bank commission {commission.ToString("N2", CultureInfo.InvariantCulture)} {destAccount.Currency}"; } break; default: throw new ArgumentOutOfRangeException(nameof(mode), mode, null); } // write journals _journalService.WriteTransferJournal(sourceAccount, destAccount, sourceDescription, destDescription); // update database _databaseContext.Accounts.Update(sourceAccount); _databaseContext.Accounts.Update(destAccount); // update bank revenues, if any if (commission > 0) { _bankBalanceService.AddRevenue(commission, $"A commission for money transfer from the account {sourceAccount.AccountNumber} to the account {destAccount.AccountNumber}"); } // commit transaction transaction.Commit(); } catch { transaction.Rollback(); throw; } } }