public async Task TestListFiProfiles() { // Retrieve financial institutions var financialInstitutions = OFX2Service.ListFinancialInstitutions(); // Default empty credentials var emptyCredentials = new Credentials("",""); // Step through each, count success and failure int successCount = 0; int failureCount = 0; foreach (var fi in financialInstitutions) { var ofxService = new OFX2Service(fi, emptyCredentials); // Only test a few entries during a normal run. Each entry can take a significant amount of time to test. if (successCount + failureCount > 5) continue; try { var profiles = await ofxService.ListProfiles(); // At least 1 profile should come back if (profiles.Items.Length == 0) { // Manual diagnostics assistance Trace.WriteLine("No profiles returned for " + fi.Name + " at " + fi.ServiceEndpoint); failureCount++; } else { successCount++; } } catch (Exception) { // Any exception is a failure failureCount++; // Manual diagnostics assistance Trace.WriteLine("Failed to list profiles for " + fi.Name + " at " + fi.ServiceEndpoint); } } // At least 1 of the profiles should succed Assert.IsTrue(successCount >= 1); }
/// <summary> /// Retrieve the list of accounts from a financial institution using OFX and return all accounts that are not already present in the database /// </summary> /// <param name="financialInstitution">Financial institution to query</param> /// <param name="fiCredentials">Credentials for financial institution account</param> /// <returns>List of accounts</returns> public static async Task<IEnumerable<Account>> EnumerateNewAccounts( OFX.Types.FinancialInstitution financialInstitution, OFX.Types.Credentials fiCredentials) { using (BackgroundTaskTracker.BeginTask("Retrieving Account Information")) { var ofxService = new OFX2Service(financialInstitution, fiCredentials); var accountList = new List<Account>(); var ofxAccountList = await ofxService.ListAccounts().ConfigureAwait(false); // TODO: If ofxAccountList is null, raise a more detailed exception using (var dataService = new DataService()) { foreach (var ofxAccount in ofxAccountList) { // Convert from OFX account type to db account type and encode account id AccountType accountType = AccountType.Checking; string accountId = ""; if (ofxAccount.GetType() == typeof (OFX.Types.CheckingAccount)) { accountType = AccountType.Checking; accountId = ((OFX.Types.CheckingAccount) ofxAccount).RoutingId + ":" + ofxAccount.AccountId; } else if (ofxAccount.GetType() == typeof (OFX.Types.SavingsAccount)) { accountType = AccountType.Savings; accountId = ((OFX.Types.SavingsAccount) ofxAccount).RoutingId + ":" + ofxAccount.AccountId; } else if (ofxAccount.GetType() == typeof (OFX.Types.CreditCardAccount)) { accountType = AccountType.Creditcard; accountId = ofxAccount.AccountId; } // Look for a matching account in the database if (!dataService.GetAccountByFinancialId(accountId).Any()) { // This account is not already in the DB, add to new account list accountList.Add(new Account { AccountName = accountType + ":" + ofxAccount.AccountId.Substring(ofxAccount.AccountId.Length - 4), AccountType = accountType.ToString(), Currency = "USD", FiAccountId = accountId }); } } } // Return the finalized list of new accounts return accountList; } }
/// <summary> /// Verify the provided account credentials. Raises an exception if validation fails /// </summary> /// <param name="financialInstitution">Financial institution to query</param> /// <param name="fiCredentials">Credentials for financial institution account</param> /// <returns>List of accounts</returns> public static async Task VerifyAccountCredentials(FinancialInstitution financialInstitution, OFX.Types.Credentials fiCredentials) { using (BackgroundTaskTracker.BeginTask("Verifying Credentials")) { // Convert from data model FI into OFX FI var ofxFinancialInstitition = new OFX.Types.FinancialInstitution(financialInstitution.Name, new Uri(financialInstitution.OfxUpdateUrl), financialInstitution.OfxOrganizationId, financialInstitution.OfxFinancialUnitId); var ofxService = new OFX2Service(ofxFinancialInstitition, fiCredentials); // Call list accounts to validate credentials await ofxService.ListAccounts().ConfigureAwait(false); } }
/// <summary> /// Download OFX transactions for an account and merge them into the account transaction list /// </summary> /// <param name="account">Account configured with financial institution login information</param> public static async Task DownloadOfxTransactionsForAccount(Account account) { using (BackgroundTaskTracker.BeginTask("Downloading statements")) { // Default retrieval parameters OFX2Service ofxService; OFX.Types.Account ofxAccount; var endTime = DateTimeOffset.Now; var startTime = new DateTimeOffset(new DateTime(1997, 1, 1)); 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); // Form FI connection properties for transaction retrieval var fi = new OFX.Types.FinancialInstitution( updateAccount.FinancialInstitutionUser.FinancialInstitution.Name, new Uri(updateAccount.FinancialInstitutionUser.FinancialInstitution.OfxUpdateUrl), updateAccount.FinancialInstitutionUser.FinancialInstitution.OfxOrganizationId, updateAccount.FinancialInstitutionUser.FinancialInstitution.OfxFinancialUnitId ); // Form credentials for login var credentials = new OFX.Types.Credentials( updateAccount.FinancialInstitutionUser.UserId, updateAccount.FinancialInstitutionUser.Password ); // Create service ofxService = new OFX2Service(fi, credentials); // Create proper account type for this account var accountType = (AccountType) account.AccountType; if (accountType == AccountType.Checking) { // Split routing and account id from combined string var accountIdComponents = account.FiAccountId.Split(':'); ofxAccount = new OFX.Types.CheckingAccount(accountIdComponents[0], accountIdComponents[1], "", true); } else if (accountType == AccountType.Savings) { // Split routing and account id from combined string var accountIdComponents = account.FiAccountId.Split(':'); ofxAccount = new OFX.Types.SavingsAccount(accountIdComponents[0], accountIdComponents[1], "", true); } else //if (accountType == AccountType.CREDITCARD) { ofxAccount = new OFX.Types.CreditCardAccount(account.FiAccountId, "", true); } // Use the start time of the latest transaction if we have any try { var lastTransaction = (from transaction in updateAccount.Transactions orderby transaction.Date descending select transaction).First(); startTime = new DateTimeOffset(lastTransaction.Date); } catch (InvalidOperationException) { // No transactions - ignore and use default start date. } } // Retrieve statement(s) (should only be one per protocol, but we can handle any number) var ofxStatments = await ofxService.GetStatement(ofxAccount, startTime, endTime).ConfigureAwait(false); if (!String.IsNullOrEmpty(ofxStatments.Item2) || !String.IsNullOrWhiteSpace(ofxStatments.Item2)) { MessageBox.Show(ofxStatments.Item2, "Error"); } foreach (var ofxStatement in ofxStatments.Item1) MergeStatementTransactionsIntoAccount(account, ofxStatement); } }