private static void GenerateMergedStatement(List<KeyValuePair<string, FineAntsCore.Statement>> statements, out FineAntsCore.Statement merged, out List<string> warnings) { statements.Sort(delegate(KeyValuePair<string, FineAntsCore.Statement> a, KeyValuePair<string, FineAntsCore.Statement> b) { return a.Value.StartDate.CompareTo(b.Value.StartDate); }); // create merged statement object with properties of first file in files merged = new FineAntsCore.Statement(); merged.StartDate = statements[0].Value.StartDate; merged.EndDate = statements[statements.Count - 1].Value.EndDate; merged.ClosingBalance = statements[statements.Count - 1].Value.ClosingBalance; // add all the transactions from the first document to the merged document foreach (var transaction in statements[0].Value.Transactions) { // add to transactions of merged statement merged.Transactions.Add(transaction); } warnings = new List<string>(); for (int index = 1; index < statements.Count; ++index) { int dateComparison = DateTime.Compare(statements[index].Value.StartDate, statements[index - 1].Value.EndDate.AddDays(1)); if (dateComparison < 0) { // todo: address duplicate transactions warnings.Add("overlapping date range between documents " + (statements[index - 1].Key) + " and " + statements[index].Key); } else if (dateComparison > 0) { warnings.Add("gap in date range between documents " + (statements[index - 1].Key) + " and " + statements[index].Key); } // Detect balance inaccuracies. int laterClosingBalance = statements[index].Value.ClosingBalance; int earlierClosingBalance = statements[index - 1].Value.ClosingBalance; int transactionsInBetween = sumOfTransactions(statements[index].Value); if (earlierClosingBalance + transactionsInBetween != laterClosingBalance) { warnings.Add("Document " + statements[index].Key + " has a closing balance of " + earlierClosingBalance + " which is inconsistent with its transactions (totalling " + transactionsInBetween + ") and the closing balance of " + laterClosingBalance + " in " + (statements[index - 1].Key) ); } // add all the transactions to the merged document foreach (var transaction in statements[index].Value.Transactions) { // add to transactions of merged statement merged.Transactions.Add(transaction); } } merged.Transactions.Sort(delegate(FineAntsCore.Transaction a, FineAntsCore.Transaction b) { return a.Date.CompareTo(b.Date); }); }
static FineAntsCore.Statement ConvertHSBCHTMLFileToFineAnts(FileInfo fileInfo) { HtmlAgilityPack.HtmlDocument brokenDocument = new HtmlAgilityPack.HtmlDocument(); brokenDocument.Load(fileInfo.FullName); brokenDocument.OptionOutputAsXml = true; string fixedXmlFileName = fileInfo.FullName + ".fixed.xml"; brokenDocument.Save(fixedXmlFileName); XmlDocument document = new XmlDocument(); document.Load(fixedXmlFileName); XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable); namespaceManager.AddNamespace("d", "http://www.w3.org/1999/xhtml"); XmlNode closingBalanceNode = document.SelectSingleNode("/span/d:html/d:body/d:div[@id='top']/d:div[@id='innerPage']/d:div[@id='wrapper']/d:div[@id='main']/d:div[@id='content']/d:div[@class='containerMain']/d:div[@class='hsbcMainContent hsbcCol']/d:div[@class='extContentHighlightPib hsbcCol']/d:table/d:tbody/d:tr[last()]/d:td[6]/d:p", namespaceManager); XmlNode closingBalanceSignNode = document.SelectSingleNode("/span/d:html/d:body/d:div[@id='top']/d:div[@id='innerPage']/d:div[@id='wrapper']/d:div[@id='main']/d:div[@id='content']/d:div[@class='containerMain']/d:div[@class='hsbcMainContent hsbcCol']/d:div[@class='extContentHighlightPib hsbcCol']/d:table/d:tbody/d:tr[last()]/d:td[7]/d:p", namespaceManager); int closingBalance = moneyInPenceFromString(closingBalanceNode.InnerText.Trim()); if (closingBalanceSignNode.InnerText.Trim() == "D") closingBalance = -closingBalance; XmlNode endDateNode = document.SelectSingleNode("/span/d:html/d:body/d:div[@id='top']/d:div[@id='innerPage']/d:div[@id='wrapper']/d:div[@id='main']/d:div[@id='content']/d:div[@class='containerMain']/d:div[@class='hsbcMainContent hsbcCol']/d:div[@class='extContentHighlightPib hsbcCol']/d:div[@class='extPibRow hsbcRow']/d:div[@class='hsbcPadding']/d:div[@class='hsbcTextRight']", namespaceManager); string endDateString = HtmlAgilityPack.HtmlEntity.DeEntitize(endDateNode.InnerText).Trim(); System.Globalization.CultureInfo provider = System.Globalization.CultureInfo.InvariantCulture; DateTime endDate = DateTime.ParseExact(endDateString, "dd MMM yyyy", provider); XmlNode startDateNode = document.SelectSingleNode("/span/d:html/d:body/d:div[@id='top']/d:div[@id='innerPage']/d:div[@id='wrapper']/d:div[@id='main']/d:div[@id='content']/d:div[@class='containerMain']/d:div[@class='hsbcMainContent hsbcCol']/d:div[@class='extContentHighlightPib hsbcCol']/d:table/d:tbody/d:tr[1]/d:td[1]/d:p", namespaceManager); string startDateString = HtmlAgilityPack.HtmlEntity.DeEntitize(startDateNode.InnerText).Trim(); DateTime startDate = dateFromDateStringFixedUsingUpperBoundDate(startDateString, endDate.AddDays(-1)).AddDays(1); List<FineAntsCore.Transaction> transactions = new List<FineAntsCore.Transaction>(); XmlNodeList transactionNodes = document.SelectNodes("/span/d:html/d:body/d:div[@id='top']/d:div[@id='innerPage']/d:div[@id='wrapper']/d:div[@id='main']/d:div[@id='content']/d:div[@class='containerMain']/d:div[@class='hsbcMainContent hsbcCol']/d:div[@class='extContentHighlightPib hsbcCol']/d:table/d:tbody/d:tr[position()>1 and position()<last()]", namespaceManager); foreach (XmlNode node in transactionNodes) { XmlNode dateNode = node.SelectSingleNode("d:td[1]/d:p", namespaceManager); XmlNode typeNode = node.SelectSingleNode("d:td[2]/d:p", namespaceManager); XmlNode nameNode = node.SelectSingleNode("d:td[3]/d:p", namespaceManager); XmlNode moneyOutNode = node.SelectSingleNode("d:td[4]/d:p", namespaceManager); XmlNode moneyInNode = node.SelectSingleNode("d:td[5]/d:p", namespaceManager); string date = HtmlAgilityPack.HtmlEntity.DeEntitize(dateNode.InnerText).Trim(); string name = HtmlAgilityPack.HtmlEntity.DeEntitize(getInnerTextIgnoringLinks(nameNode)); string moneyIn = HtmlAgilityPack.HtmlEntity.DeEntitize(moneyInNode.InnerText).Trim(); string moneyOut = HtmlAgilityPack.HtmlEntity.DeEntitize(moneyOutNode.InnerText).Trim(); int money = moneyIn == "" ? -moneyInPenceFromString(moneyOut) : moneyInPenceFromString(moneyIn); transactions.Add(new FineAntsCore.Transaction(money, dateFromDateStringFixedUsingUpperBoundDate(date, endDate), name, "")); } // remove the temporary fixed file System.IO.File.Delete(fixedXmlFileName); FineAntsCore.Statement statement = new FineAntsCore.Statement(transactions, startDate, endDate, closingBalance); return statement; }
static FineAntsCore.Statement ConvertHalifaxCSVFileToFineAnts(FileInfo fileInfo) { List<FineAntsCore.Transaction> transactions; TransactionsFromCSVFile(fileInfo, out transactions); DateTime latestDate; DateTime earliestDate; DateRangeFromTransactions(transactions, out latestDate, out earliestDate); // Can't get closing balance as it's not given to us anywhere, not even on the website. FineAntsCore.Statement statement = new FineAntsCore.Statement(transactions, earliestDate, latestDate, 0); return statement; }
static FineAntsCore.Statement ConvertPostOfficeCSVFileToFineAnts(FileInfo fileInfo) { List<FineAntsCore.Transaction> transactions; int closingBalance; TransactionsAndClosingBalanceFromCSVFile(fileInfo, out transactions, out closingBalance); DateTime latestDate; DateTime earliestDate; DateRangeFromTransactions(transactions, out latestDate, out earliestDate); FineAntsCore.Statement statement = new FineAntsCore.Statement(transactions, earliestDate, latestDate, closingBalance); return statement; }
static FineAntsCore.Statement ConvertSantanderTextFileToFineAnts(FileInfo fileInfo) { StreamReader reader = new StreamReader(fileInfo.FullName, Encoding.Default, false); System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.InvariantCulture; var headerLine = reader.ReadLine(); var headerLineHeader = "From: "; assert(headerLine.StartsWith(headerLineHeader), "Header line incorrectly formatted"); var fromDateString = headerLine.Substring(headerLineHeader.Length, 10).Trim(); var toDateString = headerLine.Substring(headerLineHeader.Length + 10 + 4).Trim(); var fromDate = DateTime.ParseExact(fromDateString, "dd/MM/yyyy", culture); var toDate = DateTime.ParseExact(toDateString, "dd/MM/yyyy", culture); // Next line is account information. // Or sometimes it's a blank line and the account information is on the next line. // Seems to be random so skip two lines if the first one was blank. var maybeSkipThisLine = reader.ReadLine(); if(maybeSkipThisLine.Trim() == "") { reader.ReadLine(); } var dateLineHeader = "Date: "; var descriptionLineHeader = "Description: "; var amountLineHeader = "Amount: "; var balanceLineHeader = "Balance: "; List<FineAntsCore.Transaction> transactions = new List<FineAntsCore.Transaction>(); int lastBalanceRead = 0; while(!reader.EndOfStream) { // Each entry is preceded by a blank line. reader.ReadLine(); var dateLine = reader.ReadLine(); var descriptionLine = reader.ReadLine(); var amountLine = reader.ReadLine(); var balanceLine = reader.ReadLine(); assert(dateLine.StartsWith(dateLineHeader), "Date line incorrectly formatted"); assert(descriptionLine.StartsWith(descriptionLineHeader), "Date line incorrectly formatted"); assert(amountLine.StartsWith(amountLineHeader), "Date line incorrectly formatted"); assert(balanceLine.StartsWith(balanceLineHeader), "Date line incorrectly formatted"); var dateString = dateLine.Substring(dateLineHeader.Length).Trim(); var amountString = amountLine.Substring(amountLineHeader.Length).Trim(); var balanceString = balanceLine.Substring(balanceLineHeader.Length).Trim(); var date = DateTime.ParseExact(dateString, "dd/MM/yyyy", culture); var description = descriptionLine.Substring(descriptionLineHeader.Length).Trim(); var amount = AmountFromString(amountString); var balance = AmountFromString(balanceString); //if(transactions.Count > 0) //{ // assert(lastBalanceRead == balance - amount, "Balance and amount doesn't tally"); //} lastBalanceRead = balance; transactions.Add(new FineAntsCore.Transaction(amount, date, description, "")); } // Sort transactions by date. transactions.Sort(new FineAntsCore.TransactionDateComparer()); FineAntsCore.Statement statement = new FineAntsCore.Statement(transactions, fromDate, toDate, lastBalanceRead); return statement; }
private void openNewDocument() { fileName = null; statement = new FineAntsCore.Statement(); bindControlsToDocument(); }
private void loadFile() { System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName); if (fileInfo.Extension == ".ofx") { Ofx.Document document = new Ofx.Document(fileInfo.FullName, "ofx160.dtd"); statement = document.ConvertToFineAntsStatement(); } else if (fileInfo.Extension == ".statement") { statement = FineAntsCore.Statement.DeserialiseStatement(fileInfo.FullName); } else if (fileInfo.Extension == ".statementjson") { statement = FineAntsCore.Statement.DeserialiseStatementJSON(fileInfo.FullName); } else { throw new Exception("Unsupported file type"); } bindControlsToDocument(); }
private void loadFile() { System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName); if (fileInfo.Extension == ".ofx") { Ofx.Document document = new Ofx.Document(fileInfo.FullName, "../../../external/SgmlReader/TestSuite/ofx160.dtd"); statement = document.ConvertToFineAntsStatement(); } else if (fileInfo.Extension == ".statement") { statement = FineAntsCore.Statement.DeserialiseStatement(fileInfo.FullName); } bindControlsToDocument(); }