Ejemplo n.º 1
0
        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); });
        }
Ejemplo n.º 2
0
        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;
        }
Ejemplo n.º 3
0
        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;
        }
Ejemplo n.º 4
0
        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;
        }
Ejemplo n.º 5
0
        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;
        }
Ejemplo n.º 6
0
        private void openNewDocument()
        {
            fileName = null;
            statement = new FineAntsCore.Statement();

            bindControlsToDocument();
        }
Ejemplo n.º 7
0
        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();
        }
Ejemplo n.º 8
0
        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();
        }