/// <summary> /// Instantiates an <see cref="AccountManager"/> /// </summary> /// <param name="settings"></param> /// <param name="transactionProcessor"></param> /// <param name="repositoryFactory"></param> /// <param name="account"></param> public AccountManager(IAccountManagementSettings settings, ITransactionProcessor transactionProcessor, IAccountRepositoryFactory repositoryFactory, CashAccount account) { _settings = settings; _transactionProcessor = transactionProcessor; _repositoryFactory = repositoryFactory; _account = account; }
public void Initialize() { _settings = A.Fake<IAccountManagementSettings>(); A.CallTo(() => _settings.FinalizedTransactionLifetime).Returns(TimeSpan.FromDays(7)); _transactionProcessor = A.Fake<ITransactionProcessor>(); _repositoryFactory = A.Fake<IAccountRepositoryFactory>(); _repository = A.Fake<IAccountRepository>(); A.CallTo(() => _repositoryFactory.CreateRepository()).Returns(_repository); _account = new CashAccount(); _accountManager = new AccountManager(_settings, _transactionProcessor, _repositoryFactory, _account); }
/// <summary> /// Creates an account manager for an account /// </summary> /// <param name="account"></param> /// <returns></returns> public IAccountManager CreateAccountManager(CashAccount account) { // check that the account is not null if (account == null) throw new ArgumentNullException("account"); // check that the account has an account type if (account.AccountType == null) throw new ArgumentException(string.Format(Resources.AccountTypeNotLoadedMessage, account.Name)); // create sync manager var transactionProcessor = CreateTransactionProcessor(account.AccountType); // create account manager return new AccountManager(_settings, transactionProcessor, _repositoryFactory, account); }
/// <summary> /// Finalizes pending transactions /// </summary> public void ProcessTransactions() { lock (_accessLock) { using (var repository = _repositoryFactory.CreateRepository()) { // get the latest transaction data var account = repository.GetAccountWithTransactions(_account.Id); // update account data _account = account; // get the collection of transactions to process var transactionsToProcess = _account.Transactions .Where(t => t.StatusId == (int) TransactionStatusType.Pending && t.FinalizationDateTime <= DateTime.Now) .ToList(); // set transactions to in progress transactionsToProcess.ForEach(t => t.StatusId = (int) TransactionStatusType.InProgress); // save the changes repository.SaveChanges(); // update pending transactions _account.Balance += transactionsToProcess.Sum(t => UpdateBalanceFromPendingTransaction(t)); // remove completed/canceled transactions foreach ( var completedTransaction in _account.Transactions.Where( t => DateTime.Now - t.FinalizationDateTime >= _settings.FinalizedTransactionLifetime && (t.StatusId == (int) TransactionStatusType.Completed || t.StatusId == (int) TransactionStatusType.Cancelled)).ToList()) { // remove from account _account.Transactions.Remove(completedTransaction); // mark for deletion in repository repository.CashAccountTransactions.Remove(completedTransaction); } // save changes made to the account repository.SaveChanges(); } } }
public void ProcessTransactions_ShouldNotProcessInProgressTransaction() { // create new cancelled transaction var inProgressTransaction = new CashAccountTransaction { Amount = 500, FinalizationDateTime = DateTime.Now.AddDays(-1), StatusId = (int)TransactionStatusType.InProgress }; // create account with old transaction var account = new CashAccount { Balance = 500, Transactions = new Collection<CashAccountTransaction> { inProgressTransaction } }; // return account when retrieving from the repository A.CallTo(() => _repository.GetAccountWithTransactions(A<int>.Ignored)).Returns(account); // process transactions for the account _accountManager.ProcessTransactions(); // transactions should be retrieved from the repository A.CallTo(() => _repository.GetAccountWithTransactions(A<int>.Ignored)).MustHaveHappened(); // account should have been updated var newAccount = _accountManager.GetFieldValue<CashAccount>("_account"); newAccount.Should().Be(account); // ensure the transaction was processed A.CallTo(() => _transactionProcessor.ProcessTransaction(inProgressTransaction)).MustNotHaveHappened(); // check that transactions are as expected newAccount.Transactions.Should().Contain(t => t == inProgressTransaction); // check that balance was updated correctly newAccount.Balance.Should().Be(500); }
public void ProcessTransactions_ShouldNotRemoveNewCompletedTransaction() { // create new cancelled transaction var newCompletedTransaction = new CashAccountTransaction { FinalizationDateTime = DateTime.Now.AddDays(-1), StatusId = (int)TransactionStatusType.Completed }; // create account with old transaction var account = new CashAccount { Transactions = new Collection<CashAccountTransaction> { newCompletedTransaction } }; // return account when retrieving from the repository A.CallTo(() => _repository.GetAccountWithTransactions(A<int>.Ignored)).Returns(account); // process transactions for the account _accountManager.ProcessTransactions(); // transactions should be retrieved from the repository A.CallTo(() => _repository.GetAccountWithTransactions(A<int>.Ignored)).MustHaveHappened(); // account should have been updated var newAccount = _accountManager.GetFieldValue<CashAccount>("_account"); newAccount.Should().Be(account); // check that transactions are as expected newAccount.Transactions.Should().Contain(t => t == newCompletedTransaction); }