public void TestDeleteTransaction() { // Transaction to delete var transaction = new Transaction { Amount = 100, CategoryName = "TestCat", Description = "TestDesc", FiTransactionId = "TRN1" }; // Mock for Entity() call on context var mockEntityEntry = new Mock<DbEntityEntry<Transaction>>(); mockEntityEntry.SetupAllProperties(); // Mock setup for DataService var mockTransactionSet = new Mock<DbSet<Transaction>>(); var mockContext = new Mock<SoCashDbContext>(); mockContext.Setup(m => m.Set<Transaction>()).Returns(mockTransactionSet.Object); // Delete the transaction using (var service = new DataService(mockContext.Object)) service.DeleteTransaction(transaction); // Verify that the service removed the transaction on the mock db exactly once mockTransactionSet.Verify(m => m.Remove(transaction), Times.Once()); // Verify that the transaction ended properly mockContext.Verify(m => m.SaveChanges(), Times.Once()); }
public void TestUpdateTransaction() { // Transaction used for test var transaction = new Transaction { Amount = 100, CategoryName = "TestCat", Description = "TestDesc", FiTransactionId = "TRN1" }; // Mock setup for DataService var mockTransactionSet = new Mock<DbSet<Transaction>>(); var mockContext = new Mock<SoCashDbContext>(); mockContext.Setup(m => m.Set<Transaction>()).Returns(mockTransactionSet.Object); // Update the transaction using (var service = new DataService(mockContext.Object)) service.UpdateTransaction(transaction); // Verify that the service joined the transaction to the session in a modified state mockContext.Verify(m => m.SetModified(transaction), Times.Once()); // Verify that the transaction ended properly mockContext.Verify(m => m.SaveChanges(), Times.Once()); }
public void TestAddTransaction() { // Mock setup for DataService var mockAccountSet = new Mock<DbSet<Account>>(); var mockTransactionSet = new Mock<ICollection<Transaction>>(); var mockContext = new Mock<SoCashDbContext>(); // Account containing mock transaction set var account = new Account {Transactions = mockTransactionSet.Object}; // Place mock account into mock account list var data = new List<Account> { account }; mockAccountSet.As<IQueryable<Account>>().Setup(m => m.Provider).Returns(data.AsQueryable().Provider); mockAccountSet.As<IQueryable<Account>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression); mockAccountSet.As<IQueryable<Account>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType); mockAccountSet.As<IQueryable<Account>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); mockContext.Setup(m => m.Accounts).Returns(mockAccountSet.Object); // Transaction to add var newTransaction = new Transaction { Amount = 100, CategoryName = "TestCat", Description = "TestDesc", FiTransactionId = "TRN1" }; // Add the transaction using (var service = new DataService(mockContext.Object)) { service.AddTransaction(account, newTransaction); } // Verify that the service added the transaction on the mock db exactly once mockTransactionSet.Verify(m => m.Add(newTransaction), Times.Once()); // Verify that the transaction ended properly mockContext.Verify(m => m.SaveChanges(), Times.Once()); }
/// <summary> /// Merge transactions from the provided statement into the specified account /// </summary> /// <param name="account">The account into which transactions will be merged</param> /// <param name="statement">The statement containing the transactions to merge. The statement owning account ID must match the ID of the passed account.</param> public static void MergeStatementTransactionsIntoAccount(Account account, OFX.Types.Statement statement) { using (BackgroundTaskTracker.BeginTask("Processing Transactions")) { using (var dataService = new DataService()) { // Retrieve matching account from DB - we need to get an entity in the current db session var updateAccount = dataService.GetAccountById(account.AccountId); // If the account has no account ID set, set it from the imported statement if (updateAccount.FiAccountId == null) updateAccount.FiAccountId = statement.OwningAccount.AccountId; else if (updateAccount.FiAccountId != statement.OwningAccount.AccountId) { // TODO: Raise an error - this statement does not match the specified account. } // Add each transaction, and keep track of the earliest and latest dates DateTimeOffset earliestTransaction = DateTimeOffset.MaxValue; DateTimeOffset latestTransaction = DateTimeOffset.MinValue; foreach (var transaction in statement.Transactions) { // Update date of earliest and latest transaction if (earliestTransaction > transaction.PostDate) earliestTransaction = transaction.PostDate; if (latestTransaction < transaction.PostDate) latestTransaction = transaction.PostDate; // See if transaction is already in db try { var existingTransaction = updateAccount.Transactions.First(t => t.FiTransactionId == transaction.TransactionId); // Ensure amount and date of transaction match existingTransaction.Amount = transaction.Amount; existingTransaction.Date = transaction.PostDate.Date; } catch (InvalidOperationException) { // No such transaction, add entity // Create model transaction var dbTransaction = new Transaction { Amount = transaction.Amount, CategoryName = "", Date = transaction.PostDate.Date, Description = transaction.Name, FiTransactionId = transaction.TransactionId, }; updateAccount.Transactions.Add(dbTransaction); } } // Sum all transactions in the data set and ensure the balance on the date of the end of the statement matches the reported balance var dbBalance = updateAccount.Transactions.Where(t => t.Date <= latestTransaction) .Sum(t => t.Amount); if (dbBalance != statement.AccountBalance) { // Need to add or modify a filler transaction try { // Look for a pre-existing filler transaction as the transaction prior to the start of this statement var fillerTransaction = updateAccount.Transactions.Where(t => t.Date < earliestTransaction) .OrderByDescending(t => t.Date) .First(); // If this is not a balance adjustment transaction, move to creating a new transaction to adjust if (fillerTransaction.Description != "Balance Adjustment") throw new InvalidOperationException(); // An existing balance adjustment is in place. Modify; fillerTransaction.Amount += (statement.AccountBalance - dbBalance); } catch (InvalidOperationException) { // Determine date of filler - don't use a date in the future var fillerDate = (earliestTransaction - new TimeSpan(1, 0, 0, 0)).DateTime; if (fillerDate > DateTime.Now) fillerDate = DateTime.Now; // No existing balance adjustment transaction exists. Add one. var fillerTransaction = new Transaction { Amount = (statement.AccountBalance - dbBalance), CategoryName = "BALADJUST", Description = "Balance Adjustment", FiTransactionId = Guid.NewGuid().ToString(), Date = fillerDate }; updateAccount.Transactions.Add(fillerTransaction); } } } } }
/// <summary> /// Update values of an existing transaction /// Called from the UI for edits /// </summary> /// <param name="transaction">Modified transaction</param> public void UpdateTransaction(Transaction transaction) { // Attach to context and mark as modified DbContext.SetModified(transaction); }
/// <summary> /// Delete a transaction from the database /// Called from the UI for manual entry /// </summary> /// <param name="transaction">Transaction to delete</param> public void DeleteTransaction(Transaction transaction) { // Add the transaction to the context in unchanged state creating a current reference DbContext.SetUnchanged(transaction); // Delete from database DbContext.Set<Transaction>().Remove(transaction); }
/// <summary> /// Add a new transaction to an account. /// Called from the UI for manual entry /// </summary> /// <param name="account">Account to add transactions to</param> /// <param name="transaction">Transaction to add</param> public void AddTransaction(Account account, Transaction transaction) { // Retrieve matching account from DB - we need to get an entity in the current db session var updateAccount = DbContext.Accounts.First(dbAccount => dbAccount.AccountId == account.AccountId); updateAccount.Transactions.Add(transaction); }