diff --git a/securities.go b/securities.go index b0760a5..16b6672 100644 --- a/securities.go +++ b/securities.go @@ -18,7 +18,7 @@ type Security struct { Name string // Number of decimal digits (to the right of the decimal point) this // security is precise to - Precision int64 + Precision int Type int64 } diff --git a/static/account_register.js b/static/account_register.js index d03ba5d..261d93b 100644 --- a/static/account_register.js +++ b/static/account_register.js @@ -50,10 +50,12 @@ const TransactionRow = React.createClass({ } var amount = "$" + thisAccountSplit.Amount.toFixed(security.Precision); + var balance = "$" + this.props.transaction.Balance.toFixed(security.Precision); status = TransactionStatusMap[this.props.transaction.Status]; number = thisAccountSplit.Number; } else { var amount = "$" + (new Big(0.0)).toFixed(security.Precision); + var balance = "$" + (new Big(0.0)).toFixed(security.Precision); } return ( @@ -64,7 +66,7 @@ const TransactionRow = React.createClass({ {accountName} {status} {amount} - $??.?? + {balance} ); } }); @@ -346,21 +348,33 @@ const AccountRegister = React.createClass({ url: "account/"+account.AccountId+"/transactions?sort=date-desc&limit="+this.state.pageSize+"&page="+page, success: function(data, status, jqXHR) { var e = new Error(); - var transactions = []; e.fromJSON(data); if (e.isError()) { this.setState({error: e}); - } else { - for (var i = 0; i < data.transactions.length; i++) { - var t = new Transaction(); - t.fromJSON(data.transactions[i]); - transactions.push(t); + return; + } + + var transactions = []; + var balance = new Big(data.BeginningBalance); + + for (var i = 0; i < data.Transactions.length; i++) { + var t = new Transaction(); + t.fromJSON(data.Transactions[i]); + + // Keep a talley of the running balance of these transactions + for (var j = 0; j < data.Transactions[i].Splits.length; j++) { + var split = data.Transactions[i].Splits[j]; + if (this.props.selectedAccount.AccountId == split.AccountId) { + balance = balance.plus(split.Amount); + } } + t.Balance = balance.plus(0); // Make a copy + transactions.push(t); } var a = new Account(); - a.fromJSON(data.account); + a.fromJSON(data.Account); - var pages = Math.ceil(data.totaltransactions / this.state.pageSize); + var pages = Math.ceil(data.TotalTransactions / this.state.pageSize); this.setState({ transactions: transactions, diff --git a/transactions.go b/transactions.go index ccb249d..718823f 100644 --- a/transactions.go +++ b/transactions.go @@ -24,15 +24,19 @@ type Split struct { Debit bool } -func (s *Split) GetAmount() (*big.Rat, error) { +func GetBigAmount(amt string) (*big.Rat, error) { var r big.Rat - _, success := r.SetString(s.Amount) + _, success := r.SetString(amt) if !success { - return nil, errors.New("Couldn't convert Split.Amount to big.Rat via SetString()") + return nil, errors.New("Couldn't convert string amount to big.Rat via SetString()") } return &r, nil } +func (s *Split) GetAmount() (*big.Rat, error) { + return GetBigAmount(s.Amount) +} + func (s *Split) Valid() bool { _, err := s.GetAmount() return err == nil @@ -59,9 +63,11 @@ type TransactionList struct { } type AccountTransactionsList struct { - Account *Account `json:"account"` - Transactions *[]Transaction `json:"transactions"` - TotalTransactions int64 `json:"totaltransactions"` + Account *Account + Transactions *[]Transaction + TotalTransactions int64 + BeginningBalance string + EndingBalance string } func (t *Transaction) Write(w http.ResponseWriter) error { @@ -567,12 +573,27 @@ func GetAccountTransactions(user *User, accountid int64, sort string, page uint6 } atl.Transactions = &transactions + var pageDifference, tmp big.Rat for i := range transactions { _, err = transaction.Select(&transactions[i].Splits, "SELECT * FROM splits where TransactionId=?", transactions[i].TransactionId) if err != nil { transaction.Rollback() return nil, err } + + // Sum up the amounts from the splits we're returning so we can return + // an ending balance + for j := range transactions[i].Splits { + if transactions[i].Splits[j].AccountId == accountid { + rat_amount, err := GetBigAmount(transactions[i].Splits[j].Amount) + if err != nil { + transaction.Rollback() + return nil, err + } + tmp.Add(&pageDifference, rat_amount) + pageDifference.Set(&tmp) + } + } } count, err := transaction.SelectInt("SELECT count(DISTINCT transactions.TransactionId) FROM transactions INNER JOIN splits ON transactions.TransactionId = splits.TransactionId WHERE transactions.UserId=? AND splits.AccountId=?", user.UserId, accountid) @@ -582,6 +603,34 @@ func GetAccountTransactions(user *User, accountid int64, sort string, page uint6 } atl.TotalTransactions = count + security := GetSecurity(atl.Account.SecurityId) + if security == nil { + return nil, errors.New("Security not found") + } + + // Sum all the splits for all transaction splits for this account that + // occurred before the page we're returning + var amounts []string + sql = "SELECT splits.Amount FROM splits WHERE splits.AccountId=? AND splits.TransactionId IN (SELECT DISTINCT transactions.TransactionId FROM transactions INNER JOIN splits ON transactions.TransactionId = splits.TransactionId WHERE transactions.UserId=? AND splits.AccountId=?" + sqlsort + " LIMIT ?)" + _, err = transaction.Select(&amounts, sql, accountid, user.UserId, accountid, page*limit) + if err != nil { + transaction.Rollback() + return nil, err + } + + var balance big.Rat + for _, amount := range amounts { + rat_amount, err := GetBigAmount(amount) + if err != nil { + transaction.Rollback() + return nil, err + } + tmp.Add(&balance, rat_amount) + balance.Set(&tmp) + } + atl.BeginningBalance = balance.FloatString(security.Precision) + atl.EndingBalance = tmp.Add(&balance, &pageDifference).FloatString(security.Precision) + err = transaction.Commit() if err != nil { transaction.Rollback()