/// <summary>
        /// Find the best category match for given payee and amount from past history of transactions and splits.
        /// </summary>
        /// <param name="t">The current transaction</param>
        /// <param name="payeeOrTransferCaption">The payee we are matching</param>
        /// <returns></returns>
        public static object AutoCategoryMatch(Transaction t, string payeeOrTransferCaption)
        {
            MyMoney money = t.MyMoney;
            object  found = null;
            Account a     = t.Account;

            if (a != null)
            {
                AutoCategorization ac = new AutoCategorization();
                found = ac.FindPreviousTransactionByPayee(a, t, payeeOrTransferCaption);
                if (found == null)
                {
                    // try other accounts;
                    foreach (Account other in money.payeeAccountIndex.FindAccountsRelatedToPayee(payeeOrTransferCaption))
                    {
                        found = ac.FindPreviousTransactionByPayee(other, t, payeeOrTransferCaption);
                        if (found != null)
                        {
                            break;
                        }
                    }
                }
            }
            return(found);
        }
Exemple #2
0
        public void Save(MyMoney money)
        {
            StreamWriter writer = null;

            try
            {
                writer = new StreamWriter(this.fileName);
                WriteTransactionHeader(writer);

                if (rows != null)
                {
                    foreach (Transaction t in rows)
                    {
                        if (t != null)
                        {
                            WriteTransaction(writer, t);
                        }
                    }
                }
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                    writer = null;
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Import the Transactions & accounts in the given file and return the first account.
        /// </summary>
        /// <param name="file"></param>
        /// <param name="count"></param>
        /// <returns></returns>

        public static int ImportCsv(MyMoney myMoney, Account acct, string file)
        {
            var uri       = new Uri(file);
            var csvReader = new CsvReader(uri, Encoding.UTF8, null, 4096);

            csvReader.Delimiter = ',';
            int total = 0;

            while (csvReader.Read())
            {
                if (csvReader.FieldCount != 3)
                {
                    throw new NotSupportedException("Invalid CSV format expecting 3 columns [Date, Payee, Amount]");
                }

                var field1Date   = csvReader[0];
                var field2Payee  = csvReader[1];
                var field3Amount = csvReader[2];
                if (total == 0)
                {
                    if (field1Date != "Date" || field2Payee != "Payee" || field3Amount != "Amount")
                    {
                        throw new NotSupportedException("Invalid CSV format The fist row is expected to be the header [Date, Payee, Amount]");
                    }
                }
                else
                {
                    var dateTokens = field1Date.Split('-');

                    if (dateTokens.Length != 3)
                    {
                        throw new NotSupportedException("Invalid CSV format The Date needs to be specified in ISO8601 YYYY-MM-DD format : " + field1Date);
                    }

                    if (dateTokens[0].Length != 4)
                    {
                        throw new NotSupportedException("Invalid CSV format The Date Year must be 4 digits : " + field1Date);
                    }

                    Transaction t = myMoney.Transactions.NewTransaction(acct);

                    t.Id     = -1;
                    t.Date   = DateTime.Parse(field1Date);
                    t.Payee  = t.Payee = myMoney.Payees.FindPayee(field2Payee, true);
                    t.Amount = decimal.Parse(field3Amount);

                    myMoney.Transactions.Add(t);
                }
                total++;
            }
            csvReader.Close();

            return(total);
        }
Exemple #4
0
        public static decimal CalculateTheBalances(MyMoney money, Account account, ObservableCollection <LoanPaymentAggregation> loanPayementsView)
        {
            decimal runningBalance = 0;

            foreach (LoanPaymentAggregation l in loanPayementsView)
            {
                //-------------------------------------------------------------
                // Check to see if we need to re-calculate
                // the Principal & Interest amounts using the Percentage
                //
                if (l.Principal == 0 && l.Interest == 0 && l.Percentage != 0)
                {
                    //
                    // Recalculate the Interest using the Percentage
                    //
                    l.Interest = runningBalance * (l.Percentage / 100) / 12;

                    // and the Principal if we know the total original Payment
                    l.Principal = l.Payment - l.Interest;
                }

                if (l.Interest != 0 && runningBalance != 0)
                {
                    // Reverse calculation of the interest rate
                    LoanPaymentAggregation.CalculatePercentageOfInterest(runningBalance, l);
                }

                // Reduce the debt by the amount of the Principal paid

                //
                // -1 will reverse the amount if this is a mortgage it will change this to -900 * -1 == 900
                //
                runningBalance += l.Principal * -1;

                // Snap shot the balance due at each payment
                l.Balance = runningBalance;
            }

            return(runningBalance);
        }
        private object FindPreviousTransactionByPayee(Account a, Transaction t, string payeeOrTransferCaption)
        {
            MyMoney             money = t.MyMoney;
            IList <Transaction> list  = money.Transactions.GetTransactionsFrom(a);
            int len = list.Count;

            if (len == 0)
            {
                // Nothing to do here
                return(null);
            }

            // Tally of how close the current transaction is to the amounts for a given category or split.
            singleNeighbors = new KNearestNeighbor <Category>();
            splitNeighbors  = new KNearestNeighbor <Category>();
            splitCount      = normalCount = 0;

            Transaction closestByDate = null;
            long        ticks         = 0;

            decimal amount = t.Amount;

            for (int i = 0; i < len; i++)
            {
                Transaction u = list[i] as Transaction;
                if (amount == 0)
                {
                    // we can't use the probabilities when the amount is zero, so we just return
                    // the closest transaction by date because in the case of something like a paycheck
                    // the most recent paycheck usually has the closest numbers on the splits.
                    long newTicks = Math.Abs((u.Date - t.Date).Ticks);
                    if (closestByDate == null || newTicks < ticks)
                    {
                        closestByDate = u;
                        ticks         = newTicks;
                    }
                }
                else
                {
                    AddPossibility(t, u, payeeOrTransferCaption);
                }
            }

            if (closestByDate != null)
            {
                return(closestByDate);
            }

            IEnumerable <Tuple <object, Category> > result = null;

            if (splitCount > normalCount)
            {
                result = splitNeighbors.GetNearestNeighbors(1, t.Amount);
            }
            else
            {
                result = singleNeighbors.GetNearestNeighbors(1, t.Amount);
            }

            if (result != null && result.Any())
            {
                var first = result.First();
                var it    = first.Item1 as Transaction;
                if (it != null && it.IsSplit)
                {
                    closestByDate = null;
                    ticks         = 0;

                    // if this is a "Split" transaction, then we should grab the closest date
                    // so that the copied splits have the best chance of matching.
                    // (e.g. in a split paycheck scenario)
                    foreach (var u in list)
                    {
                        if (u.IsSplit && u.PayeeOrTransferCaption == t.PayeeOrTransferCaption)
                        {
                            long newTicks = Math.Abs((u.Date - t.Date).Ticks);
                            if (closestByDate == null || newTicks < ticks)
                            {
                                closestByDate = u;
                                ticks         = newTicks;
                            }
                        }
                    }
                    return(closestByDate);
                }

                return(first.Item1);
            }

            return(null);
        }
Exemple #6
0
 /// <summary>
 /// Compute capital gains associated with stock sales and whether they are long term or short term gains.
 /// </summary>
 /// <param name="money">The transactions</param>
 /// <param name="year">The year for the report</param>
 public CostBasisCalculator(MyMoney money, DateTime toDate)
 {
     this.myMoney = money;
     this.toDate  = toDate;
     Calculate();
 }
Exemple #7
0
        /// <summary>
        /// Loans are built from 2 Categories - Principal + Interested
        /// </summary>
        /// <param name="toDate"></param>
        static public ObservableCollection <LoanPaymentAggregation> GetLoanPayementsAggregation(MyMoney money, Account a)
        {
            ObservableCollection <LoanPaymentAggregation> view = new ObservableCollection <LoanPaymentAggregation>();

            Category categoryPrincipal = a.CategoryForPrincipal;
            Category categoryInterest  = a.CategoryForInterest;

            //-----------------------------------------------------------------
            // Get the loan transaction related to the 2 categories set
            // to this account. Category for Principal & Category for Interest
            //
            foreach (Transaction t in money.Transactions.GetAllTransactions())
            {
                if (t.Splits != null && t.Splits.Count > 0)
                {
                    foreach (Split s in t.Splits)
                    {
                        if (s.Category != null)
                        {
                            AddPaymentIfMatchingCategoriesForPrincipalOrInterest(view, s.Category, categoryPrincipal, categoryInterest, t, s, t.Account, t.Date, s.Amount);
                        }
                    }
                }
                else
                {
                    if (t.Category != null)
                    {
                        AddPaymentIfMatchingCategoriesForPrincipalOrInterest(view, t.Category, categoryPrincipal, categoryInterest, t, null, t.Account, t.Date, t.Amount);
                    }
                }
            }


            //-----------------------------------------------------------------
            // Additional manual entry made for this Loan
            //
            foreach (LoanPayment l in money.LoanPayments)
            {
                if (!l.IsDeleted)
                {
                    if (l.AccountId == a.Id)
                    {
                        LoanPaymentAggregation lp = new LoanPaymentAggregation();
                        lp.Account   = a;
                        lp.Date      = l.Date;
                        lp.Principal = l.Principal;
                        lp.Interest  = l.Interest;
                        lp.Payment   = l.Principal + l.Interest;
                        lp.LoanPayementManualEntry = l;

                        view.Add(lp);
                    }
                }
            }



            //-----------------------------------------------------------------
            // Sort and recalculate the running balance for all the payment made
            // to this Loan
            //
            var sorted = from item in view
                         orderby item.Date ascending
                         select item;

            ObservableCollection <LoanPaymentAggregation> list = new ObservableCollection <LoanPaymentAggregation>(sorted);

            // cannot carry a credit on a loan account, so if the balance is > 0 make it 0.
            a.Balance = CalculateTheBalances(money, a, list);

            return(list);
        }