mirror of
				https://github.com/aclindsa/moneygo.git
				synced 2025-11-03 18:13:27 -05:00 
			
		
		
		
	Split accounts and transactions into models
This commit is contained in:
		@@ -36,10 +36,10 @@ func GetDbMap(db *sql.DB, dbtype config.DbType) (*gorp.DbMap, error) {
 | 
				
			|||||||
	dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
 | 
						dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
 | 
				
			||||||
	dbmap.AddTableWithName(models.User{}, "users").SetKeys(true, "UserId")
 | 
						dbmap.AddTableWithName(models.User{}, "users").SetKeys(true, "UserId")
 | 
				
			||||||
	dbmap.AddTableWithName(models.Session{}, "sessions").SetKeys(true, "SessionId")
 | 
						dbmap.AddTableWithName(models.Session{}, "sessions").SetKeys(true, "SessionId")
 | 
				
			||||||
	dbmap.AddTableWithName(handlers.Account{}, "accounts").SetKeys(true, "AccountId")
 | 
						dbmap.AddTableWithName(models.Account{}, "accounts").SetKeys(true, "AccountId")
 | 
				
			||||||
	dbmap.AddTableWithName(models.Security{}, "securities").SetKeys(true, "SecurityId")
 | 
						dbmap.AddTableWithName(models.Security{}, "securities").SetKeys(true, "SecurityId")
 | 
				
			||||||
	dbmap.AddTableWithName(handlers.Transaction{}, "transactions").SetKeys(true, "TransactionId")
 | 
						dbmap.AddTableWithName(models.Transaction{}, "transactions").SetKeys(true, "TransactionId")
 | 
				
			||||||
	dbmap.AddTableWithName(handlers.Split{}, "splits").SetKeys(true, "SplitId")
 | 
						dbmap.AddTableWithName(models.Split{}, "splits").SetKeys(true, "SplitId")
 | 
				
			||||||
	dbmap.AddTableWithName(handlers.Price{}, "prices").SetKeys(true, "PriceId")
 | 
						dbmap.AddTableWithName(handlers.Price{}, "prices").SetKeys(true, "PriceId")
 | 
				
			||||||
	rtable := dbmap.AddTableWithName(handlers.Report{}, "reports").SetKeys(true, "ReportId")
 | 
						rtable := dbmap.AddTableWithName(handlers.Report{}, "reports").SetKeys(true, "ReportId")
 | 
				
			||||||
	rtable.ColMap("Lua").SetMaxSize(handlers.LuaMaxLength + luaMaxLengthBuffer)
 | 
						rtable.ColMap("Lua").SetMaxSize(handlers.LuaMaxLength + luaMaxLengthBuffer)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,127 +1,14 @@
 | 
				
			|||||||
package handlers
 | 
					package handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/models"
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type AccountType int64
 | 
					func GetAccount(tx *Tx, accountid int64, userid int64) (*models.Account, error) {
 | 
				
			||||||
 | 
						var a models.Account
 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	Bank       AccountType = 1 // start at 1 so that the default (0) is invalid
 | 
					 | 
				
			||||||
	Cash                   = 2
 | 
					 | 
				
			||||||
	Asset                  = 3
 | 
					 | 
				
			||||||
	Liability              = 4
 | 
					 | 
				
			||||||
	Investment             = 5
 | 
					 | 
				
			||||||
	Income                 = 6
 | 
					 | 
				
			||||||
	Expense                = 7
 | 
					 | 
				
			||||||
	Trading                = 8
 | 
					 | 
				
			||||||
	Equity                 = 9
 | 
					 | 
				
			||||||
	Receivable             = 10
 | 
					 | 
				
			||||||
	Payable                = 11
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var AccountTypes = []AccountType{
 | 
					 | 
				
			||||||
	Bank,
 | 
					 | 
				
			||||||
	Cash,
 | 
					 | 
				
			||||||
	Asset,
 | 
					 | 
				
			||||||
	Liability,
 | 
					 | 
				
			||||||
	Investment,
 | 
					 | 
				
			||||||
	Income,
 | 
					 | 
				
			||||||
	Expense,
 | 
					 | 
				
			||||||
	Trading,
 | 
					 | 
				
			||||||
	Equity,
 | 
					 | 
				
			||||||
	Receivable,
 | 
					 | 
				
			||||||
	Payable,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (t AccountType) String() string {
 | 
					 | 
				
			||||||
	switch t {
 | 
					 | 
				
			||||||
	case Bank:
 | 
					 | 
				
			||||||
		return "Bank"
 | 
					 | 
				
			||||||
	case Cash:
 | 
					 | 
				
			||||||
		return "Cash"
 | 
					 | 
				
			||||||
	case Asset:
 | 
					 | 
				
			||||||
		return "Asset"
 | 
					 | 
				
			||||||
	case Liability:
 | 
					 | 
				
			||||||
		return "Liability"
 | 
					 | 
				
			||||||
	case Investment:
 | 
					 | 
				
			||||||
		return "Investment"
 | 
					 | 
				
			||||||
	case Income:
 | 
					 | 
				
			||||||
		return "Income"
 | 
					 | 
				
			||||||
	case Expense:
 | 
					 | 
				
			||||||
		return "Expense"
 | 
					 | 
				
			||||||
	case Trading:
 | 
					 | 
				
			||||||
		return "Trading"
 | 
					 | 
				
			||||||
	case Equity:
 | 
					 | 
				
			||||||
		return "Equity"
 | 
					 | 
				
			||||||
	case Receivable:
 | 
					 | 
				
			||||||
		return "Receivable"
 | 
					 | 
				
			||||||
	case Payable:
 | 
					 | 
				
			||||||
		return "Payable"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ""
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Account struct {
 | 
					 | 
				
			||||||
	AccountId         int64
 | 
					 | 
				
			||||||
	ExternalAccountId string
 | 
					 | 
				
			||||||
	UserId            int64
 | 
					 | 
				
			||||||
	SecurityId        int64
 | 
					 | 
				
			||||||
	ParentAccountId   int64 // -1 if this account is at the root
 | 
					 | 
				
			||||||
	Type              AccountType
 | 
					 | 
				
			||||||
	Name              string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// monotonically-increasing account transaction version number. Used for
 | 
					 | 
				
			||||||
	// allowing a client to ensure they have a consistent version when paging
 | 
					 | 
				
			||||||
	// through transactions.
 | 
					 | 
				
			||||||
	AccountVersion int64 `json:"Version"`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Optional fields specifying how to fetch transactions from a bank via OFX
 | 
					 | 
				
			||||||
	OFXURL       string
 | 
					 | 
				
			||||||
	OFXORG       string
 | 
					 | 
				
			||||||
	OFXFID       string
 | 
					 | 
				
			||||||
	OFXUser      string
 | 
					 | 
				
			||||||
	OFXBankID    string // OFX BankID (BrokerID if AcctType == Investment)
 | 
					 | 
				
			||||||
	OFXAcctID    string
 | 
					 | 
				
			||||||
	OFXAcctType  string // ofxgo.acctType
 | 
					 | 
				
			||||||
	OFXClientUID string
 | 
					 | 
				
			||||||
	OFXAppID     string
 | 
					 | 
				
			||||||
	OFXAppVer    string
 | 
					 | 
				
			||||||
	OFXVersion   string
 | 
					 | 
				
			||||||
	OFXNoIndent  bool
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type AccountList struct {
 | 
					 | 
				
			||||||
	Accounts *[]Account `json:"accounts"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (a *Account) Write(w http.ResponseWriter) error {
 | 
					 | 
				
			||||||
	enc := json.NewEncoder(w)
 | 
					 | 
				
			||||||
	return enc.Encode(a)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (a *Account) Read(json_str string) error {
 | 
					 | 
				
			||||||
	dec := json.NewDecoder(strings.NewReader(json_str))
 | 
					 | 
				
			||||||
	return dec.Decode(a)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (al *AccountList) Write(w http.ResponseWriter) error {
 | 
					 | 
				
			||||||
	enc := json.NewEncoder(w)
 | 
					 | 
				
			||||||
	return enc.Encode(al)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (al *AccountList) Read(json_str string) error {
 | 
					 | 
				
			||||||
	dec := json.NewDecoder(strings.NewReader(json_str))
 | 
					 | 
				
			||||||
	return dec.Decode(al)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func GetAccount(tx *Tx, accountid int64, userid int64) (*Account, error) {
 | 
					 | 
				
			||||||
	var a Account
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := tx.SelectOne(&a, "SELECT * from accounts where UserId=? AND AccountId=?", userid, accountid)
 | 
						err := tx.SelectOne(&a, "SELECT * from accounts where UserId=? AND AccountId=?", userid, accountid)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -130,8 +17,8 @@ func GetAccount(tx *Tx, accountid int64, userid int64) (*Account, error) {
 | 
				
			|||||||
	return &a, nil
 | 
						return &a, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetAccounts(tx *Tx, userid int64) (*[]Account, error) {
 | 
					func GetAccounts(tx *Tx, userid int64) (*[]models.Account, error) {
 | 
				
			||||||
	var accounts []Account
 | 
						var accounts []models.Account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := tx.Select(&accounts, "SELECT * from accounts where UserId=?", userid)
 | 
						_, err := tx.Select(&accounts, "SELECT * from accounts where UserId=?", userid)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -142,9 +29,9 @@ func GetAccounts(tx *Tx, userid int64) (*[]Account, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Get (and attempt to create if it doesn't exist). Matches on UserId,
 | 
					// Get (and attempt to create if it doesn't exist). Matches on UserId,
 | 
				
			||||||
// SecurityId, Type, Name, and ParentAccountId
 | 
					// SecurityId, Type, Name, and ParentAccountId
 | 
				
			||||||
func GetCreateAccount(tx *Tx, a Account) (*Account, error) {
 | 
					func GetCreateAccount(tx *Tx, a models.Account) (*models.Account, error) {
 | 
				
			||||||
	var accounts []Account
 | 
						var accounts []models.Account
 | 
				
			||||||
	var account Account
 | 
						var account models.Account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Try to find the top-level trading account
 | 
						// Try to find the top-level trading account
 | 
				
			||||||
	_, err := tx.Select(&accounts, "SELECT * from accounts where UserId=? AND SecurityId=? AND Type=? AND Name=? AND ParentAccountId=? ORDER BY AccountId ASC LIMIT 1", a.UserId, a.SecurityId, a.Type, a.Name, a.ParentAccountId)
 | 
						_, err := tx.Select(&accounts, "SELECT * from accounts where UserId=? AND SecurityId=? AND Type=? AND Name=? AND ParentAccountId=? ORDER BY AccountId ASC LIMIT 1", a.UserId, a.SecurityId, a.Type, a.Name, a.ParentAccountId)
 | 
				
			||||||
@@ -170,9 +57,9 @@ func GetCreateAccount(tx *Tx, a Account) (*Account, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Get (and attempt to create if it doesn't exist) the security/currency
 | 
					// Get (and attempt to create if it doesn't exist) the security/currency
 | 
				
			||||||
// trading account for the supplied security/currency
 | 
					// trading account for the supplied security/currency
 | 
				
			||||||
func GetTradingAccount(tx *Tx, userid int64, securityid int64) (*Account, error) {
 | 
					func GetTradingAccount(tx *Tx, userid int64, securityid int64) (*models.Account, error) {
 | 
				
			||||||
	var tradingAccount Account
 | 
						var tradingAccount models.Account
 | 
				
			||||||
	var account Account
 | 
						var account models.Account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	user, err := GetUser(tx, userid)
 | 
						user, err := GetUser(tx, userid)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -180,7 +67,7 @@ func GetTradingAccount(tx *Tx, userid int64, securityid int64) (*Account, error)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tradingAccount.UserId = userid
 | 
						tradingAccount.UserId = userid
 | 
				
			||||||
	tradingAccount.Type = Trading
 | 
						tradingAccount.Type = models.Trading
 | 
				
			||||||
	tradingAccount.Name = "Trading"
 | 
						tradingAccount.Name = "Trading"
 | 
				
			||||||
	tradingAccount.SecurityId = user.DefaultCurrency
 | 
						tradingAccount.SecurityId = user.DefaultCurrency
 | 
				
			||||||
	tradingAccount.ParentAccountId = -1
 | 
						tradingAccount.ParentAccountId = -1
 | 
				
			||||||
@@ -200,7 +87,7 @@ func GetTradingAccount(tx *Tx, userid int64, securityid int64) (*Account, error)
 | 
				
			|||||||
	account.Name = security.Name
 | 
						account.Name = security.Name
 | 
				
			||||||
	account.ParentAccountId = ta.AccountId
 | 
						account.ParentAccountId = ta.AccountId
 | 
				
			||||||
	account.SecurityId = securityid
 | 
						account.SecurityId = securityid
 | 
				
			||||||
	account.Type = Trading
 | 
						account.Type = models.Trading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	a, err := GetCreateAccount(tx, account)
 | 
						a, err := GetCreateAccount(tx, account)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -212,9 +99,9 @@ func GetTradingAccount(tx *Tx, userid int64, securityid int64) (*Account, error)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Get (and attempt to create if it doesn't exist) the security/currency
 | 
					// Get (and attempt to create if it doesn't exist) the security/currency
 | 
				
			||||||
// imbalance account for the supplied security/currency
 | 
					// imbalance account for the supplied security/currency
 | 
				
			||||||
func GetImbalanceAccount(tx *Tx, userid int64, securityid int64) (*Account, error) {
 | 
					func GetImbalanceAccount(tx *Tx, userid int64, securityid int64) (*models.Account, error) {
 | 
				
			||||||
	var imbalanceAccount Account
 | 
						var imbalanceAccount models.Account
 | 
				
			||||||
	var account Account
 | 
						var account models.Account
 | 
				
			||||||
	xxxtemplate := FindSecurityTemplate("XXX", models.Currency)
 | 
						xxxtemplate := FindSecurityTemplate("XXX", models.Currency)
 | 
				
			||||||
	if xxxtemplate == nil {
 | 
						if xxxtemplate == nil {
 | 
				
			||||||
		return nil, errors.New("Couldn't find XXX security template")
 | 
							return nil, errors.New("Couldn't find XXX security template")
 | 
				
			||||||
@@ -228,7 +115,7 @@ func GetImbalanceAccount(tx *Tx, userid int64, securityid int64) (*Account, erro
 | 
				
			|||||||
	imbalanceAccount.Name = "Imbalances"
 | 
						imbalanceAccount.Name = "Imbalances"
 | 
				
			||||||
	imbalanceAccount.ParentAccountId = -1
 | 
						imbalanceAccount.ParentAccountId = -1
 | 
				
			||||||
	imbalanceAccount.SecurityId = xxxsecurity.SecurityId
 | 
						imbalanceAccount.SecurityId = xxxsecurity.SecurityId
 | 
				
			||||||
	imbalanceAccount.Type = Bank
 | 
						imbalanceAccount.Type = models.Bank
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Find/create the top-level trading account
 | 
						// Find/create the top-level trading account
 | 
				
			||||||
	ia, err := GetCreateAccount(tx, imbalanceAccount)
 | 
						ia, err := GetCreateAccount(tx, imbalanceAccount)
 | 
				
			||||||
@@ -245,7 +132,7 @@ func GetImbalanceAccount(tx *Tx, userid int64, securityid int64) (*Account, erro
 | 
				
			|||||||
	account.Name = security.Name
 | 
						account.Name = security.Name
 | 
				
			||||||
	account.ParentAccountId = ia.AccountId
 | 
						account.ParentAccountId = ia.AccountId
 | 
				
			||||||
	account.SecurityId = securityid
 | 
						account.SecurityId = securityid
 | 
				
			||||||
	account.Type = Bank
 | 
						account.Type = models.Bank
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	a, err := GetCreateAccount(tx, account)
 | 
						a, err := GetCreateAccount(tx, account)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -273,7 +160,7 @@ func (cae CircularAccountsError) Error() string {
 | 
				
			|||||||
	return "Would result in circular account relationship"
 | 
						return "Would result in circular account relationship"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func insertUpdateAccount(tx *Tx, a *Account, insert bool) error {
 | 
					func insertUpdateAccount(tx *Tx, a *models.Account, insert bool) error {
 | 
				
			||||||
	found := make(map[int64]bool)
 | 
						found := make(map[int64]bool)
 | 
				
			||||||
	if !insert {
 | 
						if !insert {
 | 
				
			||||||
		found[a.AccountId] = true
 | 
							found[a.AccountId] = true
 | 
				
			||||||
@@ -286,7 +173,7 @@ func insertUpdateAccount(tx *Tx, a *Account, insert bool) error {
 | 
				
			|||||||
			return TooMuchNestingError{}
 | 
								return TooMuchNestingError{}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var a Account
 | 
							var a models.Account
 | 
				
			||||||
		err := tx.SelectOne(&a, "SELECT * from accounts where AccountId=?", parentid)
 | 
							err := tx.SelectOne(&a, "SELECT * from accounts where AccountId=?", parentid)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return ParentAccountMissingError{}
 | 
								return ParentAccountMissingError{}
 | 
				
			||||||
@@ -329,15 +216,15 @@ func insertUpdateAccount(tx *Tx, a *Account, insert bool) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func InsertAccount(tx *Tx, a *Account) error {
 | 
					func InsertAccount(tx *Tx, a *models.Account) error {
 | 
				
			||||||
	return insertUpdateAccount(tx, a, true)
 | 
						return insertUpdateAccount(tx, a, true)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func UpdateAccount(tx *Tx, a *Account) error {
 | 
					func UpdateAccount(tx *Tx, a *models.Account) error {
 | 
				
			||||||
	return insertUpdateAccount(tx, a, false)
 | 
						return insertUpdateAccount(tx, a, false)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DeleteAccount(tx *Tx, a *Account) error {
 | 
					func DeleteAccount(tx *Tx, a *models.Account) error {
 | 
				
			||||||
	if a.ParentAccountId != -1 {
 | 
						if a.ParentAccountId != -1 {
 | 
				
			||||||
		// Re-parent splits to this account's parent account if this account isn't a root account
 | 
							// Re-parent splits to this account's parent account if this account isn't a root account
 | 
				
			||||||
		_, err := tx.Exec("UPDATE splits SET AccountId=? WHERE AccountId=?", a.ParentAccountId, a.AccountId)
 | 
							_, err := tx.Exec("UPDATE splits SET AccountId=? WHERE AccountId=?", a.ParentAccountId, a.AccountId)
 | 
				
			||||||
@@ -384,7 +271,7 @@ func AccountHandler(r *http.Request, context *Context) ResponseWriterWriter {
 | 
				
			|||||||
			return AccountImportHandler(context, r, user, accountid)
 | 
								return AccountImportHandler(context, r, user, accountid)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var account Account
 | 
							var account models.Account
 | 
				
			||||||
		if err := ReadJSON(r, &account); err != nil {
 | 
							if err := ReadJSON(r, &account); err != nil {
 | 
				
			||||||
			return NewError(3 /*Invalid Request*/)
 | 
								return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -415,7 +302,7 @@ func AccountHandler(r *http.Request, context *Context) ResponseWriterWriter {
 | 
				
			|||||||
	} else if r.Method == "GET" {
 | 
						} else if r.Method == "GET" {
 | 
				
			||||||
		if context.LastLevel() {
 | 
							if context.LastLevel() {
 | 
				
			||||||
			//Return all Accounts
 | 
								//Return all Accounts
 | 
				
			||||||
			var al AccountList
 | 
								var al models.AccountList
 | 
				
			||||||
			accounts, err := GetAccounts(context.Tx, user.UserId)
 | 
								accounts, err := GetAccounts(context.Tx, user.UserId)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Print(err)
 | 
									log.Print(err)
 | 
				
			||||||
@@ -447,7 +334,7 @@ func AccountHandler(r *http.Request, context *Context) ResponseWriterWriter {
 | 
				
			|||||||
			return NewError(3 /*Invalid Request*/)
 | 
								return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if r.Method == "PUT" {
 | 
							if r.Method == "PUT" {
 | 
				
			||||||
			var account Account
 | 
								var account models.Account
 | 
				
			||||||
			if err := ReadJSON(r, &account); err != nil || account.AccountId != accountid {
 | 
								if err := ReadJSON(r, &account); err != nil || account.AccountId != accountid {
 | 
				
			||||||
				return NewError(3 /*Invalid Request*/)
 | 
									return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const luaAccountTypeName = "account"
 | 
					const luaAccountTypeName = "account"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func luaContextGetAccounts(L *lua.LState) (map[int64]*Account, error) {
 | 
					func luaContextGetAccounts(L *lua.LState) (map[int64]*models.Account, error) {
 | 
				
			||||||
	var account_map map[int64]*Account
 | 
						var account_map map[int64]*models.Account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx := L.Context()
 | 
						ctx := L.Context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,7 +21,7 @@ func luaContextGetAccounts(L *lua.LState) (map[int64]*Account, error) {
 | 
				
			|||||||
		return nil, errors.New("Couldn't find tx in lua's Context")
 | 
							return nil, errors.New("Couldn't find tx in lua's Context")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	account_map, ok = ctx.Value(accountsContextKey).(map[int64]*Account)
 | 
						account_map, ok = ctx.Value(accountsContextKey).(map[int64]*models.Account)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		user, ok := ctx.Value(userContextKey).(*models.User)
 | 
							user, ok := ctx.Value(userContextKey).(*models.User)
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
@@ -33,7 +33,7 @@ func luaContextGetAccounts(L *lua.LState) (map[int64]*Account, error) {
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		account_map = make(map[int64]*Account)
 | 
							account_map = make(map[int64]*models.Account)
 | 
				
			||||||
		for i := range *accounts {
 | 
							for i := range *accounts {
 | 
				
			||||||
			account_map[(*accounts)[i].AccountId] = &(*accounts)[i]
 | 
								account_map[(*accounts)[i].AccountId] = &(*accounts)[i]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -69,7 +69,7 @@ func luaRegisterAccounts(L *lua.LState) {
 | 
				
			|||||||
	L.SetField(mt, "__eq", L.NewFunction(luaAccount__eq))
 | 
						L.SetField(mt, "__eq", L.NewFunction(luaAccount__eq))
 | 
				
			||||||
	L.SetField(mt, "__metatable", lua.LString("protected"))
 | 
						L.SetField(mt, "__metatable", lua.LString("protected"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, accttype := range AccountTypes {
 | 
						for _, accttype := range models.AccountTypes {
 | 
				
			||||||
		L.SetField(mt, accttype.String(), lua.LNumber(float64(accttype)))
 | 
							L.SetField(mt, accttype.String(), lua.LNumber(float64(accttype)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,7 +79,7 @@ func luaRegisterAccounts(L *lua.LState) {
 | 
				
			|||||||
	L.SetGlobal("get_accounts", getAccountsFn)
 | 
						L.SetGlobal("get_accounts", getAccountsFn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func AccountToLua(L *lua.LState, account *Account) *lua.LUserData {
 | 
					func AccountToLua(L *lua.LState, account *models.Account) *lua.LUserData {
 | 
				
			||||||
	ud := L.NewUserData()
 | 
						ud := L.NewUserData()
 | 
				
			||||||
	ud.Value = account
 | 
						ud.Value = account
 | 
				
			||||||
	L.SetMetatable(ud, L.GetTypeMetatable(luaAccountTypeName))
 | 
						L.SetMetatable(ud, L.GetTypeMetatable(luaAccountTypeName))
 | 
				
			||||||
@@ -87,9 +87,9 @@ func AccountToLua(L *lua.LState, account *Account) *lua.LUserData {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Checks whether the first lua argument is a *LUserData with *Account and returns this *Account.
 | 
					// Checks whether the first lua argument is a *LUserData with *Account and returns this *Account.
 | 
				
			||||||
func luaCheckAccount(L *lua.LState, n int) *Account {
 | 
					func luaCheckAccount(L *lua.LState, n int) *models.Account {
 | 
				
			||||||
	ud := L.CheckUserData(n)
 | 
						ud := L.CheckUserData(n)
 | 
				
			||||||
	if account, ok := ud.Value.(*Account); ok {
 | 
						if account, ok := ud.Value.(*models.Account); ok {
 | 
				
			||||||
		return account
 | 
							return account
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	L.ArgError(n, "account expected")
 | 
						L.ArgError(n, "account expected")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,19 +2,20 @@ package handlers_test
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/handlers"
 | 
						"github.com/aclindsa/moneygo/internal/handlers"
 | 
				
			||||||
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func createAccount(client *http.Client, account *handlers.Account) (*handlers.Account, error) {
 | 
					func createAccount(client *http.Client, account *models.Account) (*models.Account, error) {
 | 
				
			||||||
	var a handlers.Account
 | 
						var a models.Account
 | 
				
			||||||
	err := create(client, account, &a, "/v1/accounts/")
 | 
						err := create(client, account, &a, "/v1/accounts/")
 | 
				
			||||||
	return &a, err
 | 
						return &a, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getAccount(client *http.Client, accountid int64) (*handlers.Account, error) {
 | 
					func getAccount(client *http.Client, accountid int64) (*models.Account, error) {
 | 
				
			||||||
	var a handlers.Account
 | 
						var a models.Account
 | 
				
			||||||
	err := read(client, &a, "/v1/accounts/"+strconv.FormatInt(accountid, 10))
 | 
						err := read(client, &a, "/v1/accounts/"+strconv.FormatInt(accountid, 10))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -22,8 +23,8 @@ func getAccount(client *http.Client, accountid int64) (*handlers.Account, error)
 | 
				
			|||||||
	return &a, nil
 | 
						return &a, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getAccounts(client *http.Client) (*handlers.AccountList, error) {
 | 
					func getAccounts(client *http.Client) (*models.AccountList, error) {
 | 
				
			||||||
	var al handlers.AccountList
 | 
						var al models.AccountList
 | 
				
			||||||
	err := read(client, &al, "/v1/accounts/")
 | 
						err := read(client, &al, "/v1/accounts/")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -31,8 +32,8 @@ func getAccounts(client *http.Client) (*handlers.AccountList, error) {
 | 
				
			|||||||
	return &al, nil
 | 
						return &al, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateAccount(client *http.Client, account *handlers.Account) (*handlers.Account, error) {
 | 
					func updateAccount(client *http.Client, account *models.Account) (*models.Account, error) {
 | 
				
			||||||
	var a handlers.Account
 | 
						var a models.Account
 | 
				
			||||||
	err := update(client, account, &a, "/v1/accounts/"+strconv.FormatInt(account.AccountId, 10))
 | 
						err := update(client, account, &a, "/v1/accounts/"+strconv.FormatInt(account.AccountId, 10))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -40,7 +41,7 @@ func updateAccount(client *http.Client, account *handlers.Account) (*handlers.Ac
 | 
				
			|||||||
	return &a, nil
 | 
						return &a, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func deleteAccount(client *http.Client, a *handlers.Account) error {
 | 
					func deleteAccount(client *http.Client, a *models.Account) error {
 | 
				
			||||||
	err := remove(client, "/v1/accounts/"+strconv.FormatInt(a.AccountId, 10))
 | 
						err := remove(client, "/v1/accounts/"+strconv.FormatInt(a.AccountId, 10))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -137,7 +138,7 @@ func TestUpdateAccount(t *testing.T) {
 | 
				
			|||||||
			curr := d.accounts[i]
 | 
								curr := d.accounts[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			curr.Name = "blah"
 | 
								curr.Name = "blah"
 | 
				
			||||||
			curr.Type = handlers.Payable
 | 
								curr.Type = models.Payable
 | 
				
			||||||
			for _, s := range d.securities {
 | 
								for _, s := range d.securities {
 | 
				
			||||||
				if s.UserId == curr.UserId {
 | 
									if s.UserId == curr.UserId {
 | 
				
			||||||
					curr.SecurityId = s.SecurityId
 | 
										curr.SecurityId = s.SecurityId
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"github.com/aclindsa/moneygo/internal/config"
 | 
						"github.com/aclindsa/moneygo/internal/config"
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/db"
 | 
						"github.com/aclindsa/moneygo/internal/db"
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/handlers"
 | 
						"github.com/aclindsa/moneygo/internal/handlers"
 | 
				
			||||||
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
@@ -202,7 +203,7 @@ func uploadFile(client *http.Client, filename, urlsuffix string) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func accountBalanceHelper(t *testing.T, client *http.Client, account *handlers.Account, balance string) {
 | 
					func accountBalanceHelper(t *testing.T, client *http.Client, account *models.Account, balance string) {
 | 
				
			||||||
	t.Helper()
 | 
						t.Helper()
 | 
				
			||||||
	transactions, err := getAccountTransactions(client, account.AccountId, 0, 0, "")
 | 
						transactions, err := getAccountTransactions(client, account.AccountId, 0, 0, "")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -127,8 +127,8 @@ type GnucashXMLImport struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type GnucashImport struct {
 | 
					type GnucashImport struct {
 | 
				
			||||||
	Securities   []models.Security
 | 
						Securities   []models.Security
 | 
				
			||||||
	Accounts     []Account
 | 
						Accounts     []models.Account
 | 
				
			||||||
	Transactions []Transaction
 | 
						Transactions []models.Transaction
 | 
				
			||||||
	Prices       []Price
 | 
						Prices       []Price
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,7 +206,7 @@ func ImportGnucash(r io.Reader) (*GnucashImport, error) {
 | 
				
			|||||||
	//Translate to our account format, figuring out parent relationships
 | 
						//Translate to our account format, figuring out parent relationships
 | 
				
			||||||
	for guid := range accountMap {
 | 
						for guid := range accountMap {
 | 
				
			||||||
		ga := accountMap[guid]
 | 
							ga := accountMap[guid]
 | 
				
			||||||
		var a Account
 | 
							var a models.Account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		a.AccountId = ga.accountid
 | 
							a.AccountId = ga.accountid
 | 
				
			||||||
		if ga.ParentAccountId == rootAccount.AccountId {
 | 
							if ga.ParentAccountId == rootAccount.AccountId {
 | 
				
			||||||
@@ -229,29 +229,29 @@ func ImportGnucash(r io.Reader) (*GnucashImport, error) {
 | 
				
			|||||||
		//TODO find account types
 | 
							//TODO find account types
 | 
				
			||||||
		switch ga.Type {
 | 
							switch ga.Type {
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			a.Type = Bank
 | 
								a.Type = models.Bank
 | 
				
			||||||
		case "ASSET":
 | 
							case "ASSET":
 | 
				
			||||||
			a.Type = Asset
 | 
								a.Type = models.Asset
 | 
				
			||||||
		case "BANK":
 | 
							case "BANK":
 | 
				
			||||||
			a.Type = Bank
 | 
								a.Type = models.Bank
 | 
				
			||||||
		case "CASH":
 | 
							case "CASH":
 | 
				
			||||||
			a.Type = Cash
 | 
								a.Type = models.Cash
 | 
				
			||||||
		case "CREDIT", "LIABILITY":
 | 
							case "CREDIT", "LIABILITY":
 | 
				
			||||||
			a.Type = Liability
 | 
								a.Type = models.Liability
 | 
				
			||||||
		case "EQUITY":
 | 
							case "EQUITY":
 | 
				
			||||||
			a.Type = Equity
 | 
								a.Type = models.Equity
 | 
				
			||||||
		case "EXPENSE":
 | 
							case "EXPENSE":
 | 
				
			||||||
			a.Type = Expense
 | 
								a.Type = models.Expense
 | 
				
			||||||
		case "INCOME":
 | 
							case "INCOME":
 | 
				
			||||||
			a.Type = Income
 | 
								a.Type = models.Income
 | 
				
			||||||
		case "PAYABLE":
 | 
							case "PAYABLE":
 | 
				
			||||||
			a.Type = Payable
 | 
								a.Type = models.Payable
 | 
				
			||||||
		case "RECEIVABLE":
 | 
							case "RECEIVABLE":
 | 
				
			||||||
			a.Type = Receivable
 | 
								a.Type = models.Receivable
 | 
				
			||||||
		case "MUTUAL", "STOCK":
 | 
							case "MUTUAL", "STOCK":
 | 
				
			||||||
			a.Type = Investment
 | 
								a.Type = models.Investment
 | 
				
			||||||
		case "TRADING":
 | 
							case "TRADING":
 | 
				
			||||||
			a.Type = Trading
 | 
								a.Type = models.Trading
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		gncimport.Accounts = append(gncimport.Accounts, a)
 | 
							gncimport.Accounts = append(gncimport.Accounts, a)
 | 
				
			||||||
@@ -261,20 +261,20 @@ func ImportGnucash(r io.Reader) (*GnucashImport, error) {
 | 
				
			|||||||
	for i := range gncxml.Transactions {
 | 
						for i := range gncxml.Transactions {
 | 
				
			||||||
		gt := gncxml.Transactions[i]
 | 
							gt := gncxml.Transactions[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		t := new(Transaction)
 | 
							t := new(models.Transaction)
 | 
				
			||||||
		t.Description = gt.Description
 | 
							t.Description = gt.Description
 | 
				
			||||||
		t.Date = gt.DatePosted.Date.Time
 | 
							t.Date = gt.DatePosted.Date.Time
 | 
				
			||||||
		for j := range gt.Splits {
 | 
							for j := range gt.Splits {
 | 
				
			||||||
			gs := gt.Splits[j]
 | 
								gs := gt.Splits[j]
 | 
				
			||||||
			s := new(Split)
 | 
								s := new(models.Split)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch gs.Status {
 | 
								switch gs.Status {
 | 
				
			||||||
			default: // 'n', or not present
 | 
								default: // 'n', or not present
 | 
				
			||||||
				s.Status = Imported
 | 
									s.Status = models.Imported
 | 
				
			||||||
			case "c":
 | 
								case "c":
 | 
				
			||||||
				s.Status = Cleared
 | 
									s.Status = models.Cleared
 | 
				
			||||||
			case "y":
 | 
								case "y":
 | 
				
			||||||
				s.Status = Reconciled
 | 
									s.Status = models.Reconciled
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			account, ok := accountMap[gs.AccountId]
 | 
								account, ok := accountMap[gs.AccountId]
 | 
				
			||||||
@@ -437,7 +437,7 @@ func GnucashImportHandler(r *http.Request, context *Context) ResponseWriterWrite
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			split.AccountId = acctId
 | 
								split.AccountId = acctId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			exists, err := split.AlreadyImported(context.Tx)
 | 
								exists, err := SplitAlreadyImported(context.Tx, split)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Print("Error checking if split was already imported:", err)
 | 
									log.Print("Error checking if split was already imported:", err)
 | 
				
			||||||
				return NewError(999 /*Internal Error*/)
 | 
									return NewError(999 /*Internal Error*/)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
package handlers_test
 | 
					package handlers_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/handlers"
 | 
					 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/models"
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
@@ -32,19 +31,19 @@ func TestImportGnucash(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Next, find the Expenses/Groceries account and verify it's balance
 | 
							// Next, find the Expenses/Groceries account and verify it's balance
 | 
				
			||||||
		var income, equity, liabilities, expenses, salary, creditcard, groceries, cable, openingbalances *handlers.Account
 | 
							var income, equity, liabilities, expenses, salary, creditcard, groceries, cable, openingbalances *models.Account
 | 
				
			||||||
		accounts, err := getAccounts(d.clients[0])
 | 
							accounts, err := getAccounts(d.clients[0])
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("Error fetching accounts: %s\n", err)
 | 
								t.Fatalf("Error fetching accounts: %s\n", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for i, account := range *accounts.Accounts {
 | 
							for i, account := range *accounts.Accounts {
 | 
				
			||||||
			if account.Name == "Income" && account.Type == handlers.Income && account.ParentAccountId == -1 {
 | 
								if account.Name == "Income" && account.Type == models.Income && account.ParentAccountId == -1 {
 | 
				
			||||||
				income = &(*accounts.Accounts)[i]
 | 
									income = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Equity" && account.Type == handlers.Equity && account.ParentAccountId == -1 {
 | 
								} else if account.Name == "Equity" && account.Type == models.Equity && account.ParentAccountId == -1 {
 | 
				
			||||||
				equity = &(*accounts.Accounts)[i]
 | 
									equity = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Liabilities" && account.Type == handlers.Liability && account.ParentAccountId == -1 {
 | 
								} else if account.Name == "Liabilities" && account.Type == models.Liability && account.ParentAccountId == -1 {
 | 
				
			||||||
				liabilities = &(*accounts.Accounts)[i]
 | 
									liabilities = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Expenses" && account.Type == handlers.Expense && account.ParentAccountId == -1 {
 | 
								} else if account.Name == "Expenses" && account.Type == models.Expense && account.ParentAccountId == -1 {
 | 
				
			||||||
				expenses = &(*accounts.Accounts)[i]
 | 
									expenses = &(*accounts.Accounts)[i]
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -61,15 +60,15 @@ func TestImportGnucash(t *testing.T) {
 | 
				
			|||||||
			t.Fatalf("Couldn't find 'Expenses' account")
 | 
								t.Fatalf("Couldn't find 'Expenses' account")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for i, account := range *accounts.Accounts {
 | 
							for i, account := range *accounts.Accounts {
 | 
				
			||||||
			if account.Name == "Salary" && account.Type == handlers.Income && account.ParentAccountId == income.AccountId {
 | 
								if account.Name == "Salary" && account.Type == models.Income && account.ParentAccountId == income.AccountId {
 | 
				
			||||||
				salary = &(*accounts.Accounts)[i]
 | 
									salary = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Opening Balances" && account.Type == handlers.Equity && account.ParentAccountId == equity.AccountId {
 | 
								} else if account.Name == "Opening Balances" && account.Type == models.Equity && account.ParentAccountId == equity.AccountId {
 | 
				
			||||||
				openingbalances = &(*accounts.Accounts)[i]
 | 
									openingbalances = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Credit Card" && account.Type == handlers.Liability && account.ParentAccountId == liabilities.AccountId {
 | 
								} else if account.Name == "Credit Card" && account.Type == models.Liability && account.ParentAccountId == liabilities.AccountId {
 | 
				
			||||||
				creditcard = &(*accounts.Accounts)[i]
 | 
									creditcard = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Groceries" && account.Type == handlers.Expense && account.ParentAccountId == expenses.AccountId {
 | 
								} else if account.Name == "Groceries" && account.Type == models.Expense && account.ParentAccountId == expenses.AccountId {
 | 
				
			||||||
				groceries = &(*accounts.Accounts)[i]
 | 
									groceries = &(*accounts.Accounts)[i]
 | 
				
			||||||
			} else if account.Name == "Cable" && account.Type == handlers.Expense && account.ParentAccountId == expenses.AccountId {
 | 
								} else if account.Name == "Cable" && account.Type == models.Expense && account.ParentAccountId == expenses.AccountId {
 | 
				
			||||||
				cable = &(*accounts.Accounts)[i]
 | 
									cable = &(*accounts.Accounts)[i]
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,7 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
	// TODO Ensure all transactions have at least one split in the account
 | 
						// TODO Ensure all transactions have at least one split in the account
 | 
				
			||||||
	// we're importing to?
 | 
						// we're importing to?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var transactions []Transaction
 | 
						var transactions []models.Transaction
 | 
				
			||||||
	for _, transaction := range itl.Transactions {
 | 
						for _, transaction := range itl.Transactions {
 | 
				
			||||||
		transaction.UserId = user.UserId
 | 
							transaction.UserId = user.UserId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,7 +91,7 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
		// and fixup the SecurityId to be a valid one for this user's actual
 | 
							// and fixup the SecurityId to be a valid one for this user's actual
 | 
				
			||||||
		// securities instead of a placeholder from the import
 | 
							// securities instead of a placeholder from the import
 | 
				
			||||||
		for _, split := range transaction.Splits {
 | 
							for _, split := range transaction.Splits {
 | 
				
			||||||
			split.Status = Imported
 | 
								split.Status = models.Imported
 | 
				
			||||||
			if split.AccountId != -1 {
 | 
								if split.AccountId != -1 {
 | 
				
			||||||
				if split.AccountId != importedAccount.AccountId {
 | 
									if split.AccountId != importedAccount.AccountId {
 | 
				
			||||||
					log.Print("Imported split's AccountId wasn't -1 but also didn't match the account")
 | 
										log.Print("Imported split's AccountId wasn't -1 but also didn't match the account")
 | 
				
			||||||
@@ -101,7 +101,7 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
			} else if split.SecurityId != -1 {
 | 
								} else if split.SecurityId != -1 {
 | 
				
			||||||
				if sec, ok := securitymap[split.SecurityId]; ok {
 | 
									if sec, ok := securitymap[split.SecurityId]; ok {
 | 
				
			||||||
					// TODO try to auto-match splits to existing accounts based on past transactions that look like this one
 | 
										// TODO try to auto-match splits to existing accounts based on past transactions that look like this one
 | 
				
			||||||
					if split.ImportSplitType == TradingAccount {
 | 
										if split.ImportSplitType == models.TradingAccount {
 | 
				
			||||||
						// Find/make trading account if we're that type of split
 | 
											// Find/make trading account if we're that type of split
 | 
				
			||||||
						trading_account, err := GetTradingAccount(tx, user.UserId, sec.SecurityId)
 | 
											trading_account, err := GetTradingAccount(tx, user.UserId, sec.SecurityId)
 | 
				
			||||||
						if err != nil {
 | 
											if err != nil {
 | 
				
			||||||
@@ -110,8 +110,8 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
						}
 | 
											}
 | 
				
			||||||
						split.AccountId = trading_account.AccountId
 | 
											split.AccountId = trading_account.AccountId
 | 
				
			||||||
						split.SecurityId = -1
 | 
											split.SecurityId = -1
 | 
				
			||||||
					} else if split.ImportSplitType == SubAccount {
 | 
										} else if split.ImportSplitType == models.SubAccount {
 | 
				
			||||||
						subaccount := &Account{
 | 
											subaccount := &models.Account{
 | 
				
			||||||
							UserId:          user.UserId,
 | 
												UserId:          user.UserId,
 | 
				
			||||||
							Name:            sec.Name,
 | 
												Name:            sec.Name,
 | 
				
			||||||
							ParentAccountId: account.AccountId,
 | 
												ParentAccountId: account.AccountId,
 | 
				
			||||||
@@ -138,7 +138,7 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		imbalances, err := transaction.GetImbalances(tx)
 | 
							imbalances, err := GetTransactionImbalances(tx, &transaction)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Print(err)
 | 
								log.Print(err)
 | 
				
			||||||
			return NewError(999 /*Internal Error*/)
 | 
								return NewError(999 /*Internal Error*/)
 | 
				
			||||||
@@ -155,7 +155,7 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Add new split to fixup imbalance
 | 
									// Add new split to fixup imbalance
 | 
				
			||||||
				split := new(Split)
 | 
									split := new(models.Split)
 | 
				
			||||||
				r := new(big.Rat)
 | 
									r := new(big.Rat)
 | 
				
			||||||
				r.Neg(&imbalance)
 | 
									r.Neg(&imbalance)
 | 
				
			||||||
				security, err := GetSecurity(tx, imbalanced_security, user.UserId)
 | 
									security, err := GetSecurity(tx, imbalanced_security, user.UserId)
 | 
				
			||||||
@@ -186,7 +186,7 @@ func ofxImportHelper(tx *Tx, r io.Reader, user *models.User, accountid int64) Re
 | 
				
			|||||||
				split.SecurityId = -1
 | 
									split.SecurityId = -1
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			exists, err := split.AlreadyImported(tx)
 | 
								exists, err := SplitAlreadyImported(tx, split)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Print("Error checking if split was already imported:", err)
 | 
									log.Print("Error checking if split was already imported:", err)
 | 
				
			||||||
				return NewError(999 /*Internal Error*/)
 | 
									return NewError(999 /*Internal Error*/)
 | 
				
			||||||
@@ -251,7 +251,7 @@ func OFXImportHandler(context *Context, r *http.Request, user *models.User, acco
 | 
				
			|||||||
		return NewError(999 /*Internal Error*/)
 | 
							return NewError(999 /*Internal Error*/)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if account.Type == Investment {
 | 
						if account.Type == models.Investment {
 | 
				
			||||||
		// Investment account
 | 
							// Investment account
 | 
				
			||||||
		statementRequest := ofxgo.InvStatementRequest{
 | 
							statementRequest := ofxgo.InvStatementRequest{
 | 
				
			||||||
			TrnUID: *transactionuid,
 | 
								TrnUID: *transactionuid,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,8 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type OFXImport struct {
 | 
					type OFXImport struct {
 | 
				
			||||||
	Securities   []models.Security
 | 
						Securities   []models.Security
 | 
				
			||||||
	Accounts     []Account
 | 
						Accounts     []models.Account
 | 
				
			||||||
	Transactions []Transaction
 | 
						Transactions []models.Transaction
 | 
				
			||||||
	//	Balances     map[int64]string // map AccountIDs to ending balances
 | 
						//	Balances     map[int64]string // map AccountIDs to ending balances
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,8 +51,8 @@ func (i *OFXImport) GetAddCurrency(isoname string) (*models.Security, error) {
 | 
				
			|||||||
	return &security, nil
 | 
						return &security, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *Account) error {
 | 
					func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *models.Account) error {
 | 
				
			||||||
	var t Transaction
 | 
						var t models.Transaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Date = tran.DtPosted.UTC()
 | 
						t.Date = tran.DtPosted.UTC()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,7 +70,7 @@ func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *Account) er
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var s1, s2 Split
 | 
						var s1, s2 models.Split
 | 
				
			||||||
	if len(tran.ExtdName) > 0 {
 | 
						if len(tran.ExtdName) > 0 {
 | 
				
			||||||
		s1.Memo = tran.ExtdName.String()
 | 
							s1.Memo = tran.ExtdName.String()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -94,15 +94,15 @@ func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *Account) er
 | 
				
			|||||||
	s1.RemoteId = "ofx:" + tran.FiTID.String()
 | 
						s1.RemoteId = "ofx:" + tran.FiTID.String()
 | 
				
			||||||
	// TODO CorrectFiTID/CorrectAction?
 | 
						// TODO CorrectFiTID/CorrectAction?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s1.ImportSplitType = ImportAccount
 | 
						s1.ImportSplitType = models.ImportAccount
 | 
				
			||||||
	s2.ImportSplitType = ExternalAccount
 | 
						s2.ImportSplitType = models.ExternalAccount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security := i.Securities[account.SecurityId-1]
 | 
						security := i.Securities[account.SecurityId-1]
 | 
				
			||||||
	s1.Amount = amt.FloatString(security.Precision)
 | 
						s1.Amount = amt.FloatString(security.Precision)
 | 
				
			||||||
	s2.Amount = amt.Neg(amt).FloatString(security.Precision)
 | 
						s2.Amount = amt.Neg(amt).FloatString(security.Precision)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s1.Status = Imported
 | 
						s1.Status = models.Imported
 | 
				
			||||||
	s2.Status = Imported
 | 
						s2.Status = models.Imported
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s1.AccountId = account.AccountId
 | 
						s1.AccountId = account.AccountId
 | 
				
			||||||
	s2.AccountId = -1
 | 
						s2.AccountId = -1
 | 
				
			||||||
@@ -122,12 +122,12 @@ func (i *OFXImport) importOFXBank(stmt *ofxgo.StatementResponse) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	account := Account{
 | 
						account := models.Account{
 | 
				
			||||||
		AccountId:         int64(len(i.Accounts) + 1),
 | 
							AccountId:         int64(len(i.Accounts) + 1),
 | 
				
			||||||
		ExternalAccountId: stmt.BankAcctFrom.AcctID.String(),
 | 
							ExternalAccountId: stmt.BankAcctFrom.AcctID.String(),
 | 
				
			||||||
		SecurityId:        security.SecurityId,
 | 
							SecurityId:        security.SecurityId,
 | 
				
			||||||
		ParentAccountId:   -1,
 | 
							ParentAccountId:   -1,
 | 
				
			||||||
		Type:              Bank,
 | 
							Type:              models.Bank,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if stmt.BankTranList != nil {
 | 
						if stmt.BankTranList != nil {
 | 
				
			||||||
@@ -149,12 +149,12 @@ func (i *OFXImport) importOFXCC(stmt *ofxgo.CCStatementResponse) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	account := Account{
 | 
						account := models.Account{
 | 
				
			||||||
		AccountId:         int64(len(i.Accounts) + 1),
 | 
							AccountId:         int64(len(i.Accounts) + 1),
 | 
				
			||||||
		ExternalAccountId: stmt.CCAcctFrom.AcctID.String(),
 | 
							ExternalAccountId: stmt.CCAcctFrom.AcctID.String(),
 | 
				
			||||||
		SecurityId:        security.SecurityId,
 | 
							SecurityId:        security.SecurityId,
 | 
				
			||||||
		ParentAccountId:   -1,
 | 
							ParentAccountId:   -1,
 | 
				
			||||||
		Type:              Liability,
 | 
							Type:              models.Liability,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i.Accounts = append(i.Accounts, account)
 | 
						i.Accounts = append(i.Accounts, account)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -208,14 +208,14 @@ func (i *OFXImport) importSecurities(seclist *ofxgo.SecurityList) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetInvTran(invtran *ofxgo.InvTran) Transaction {
 | 
					func (i *OFXImport) GetInvTran(invtran *ofxgo.InvTran) models.Transaction {
 | 
				
			||||||
	var t Transaction
 | 
						var t models.Transaction
 | 
				
			||||||
	t.Description = string(invtran.Memo)
 | 
						t.Description = string(invtran.Memo)
 | 
				
			||||||
	t.Date = invtran.DtTrade.UTC()
 | 
						t.Date = invtran.DtTrade.UTC()
 | 
				
			||||||
	return t
 | 
						return t
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&buy.InvTran)
 | 
						t := i.GetInvTran(&buy.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(buy.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(buy.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -254,10 +254,10 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if num := commission.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := commission.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Commission,
 | 
								ImportSplitType: models.Commission,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -266,10 +266,10 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := taxes.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := taxes.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Taxes,
 | 
								ImportSplitType: models.Taxes,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -278,10 +278,10 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := fees.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := fees.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Fees,
 | 
								ImportSplitType: models.Fees,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -290,10 +290,10 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := load.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := load.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Load,
 | 
								ImportSplitType: models.Load,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -301,20 +301,20 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
			Amount:          load.FloatString(curdef.Precision),
 | 
								Amount:          load.FloatString(curdef.Precision),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
		Memo:            memo,
 | 
							Memo:            memo,
 | 
				
			||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: TradingAccount,
 | 
							ImportSplitType: models.TradingAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -324,10 +324,10 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var units big.Rat
 | 
						var units big.Rat
 | 
				
			||||||
	units.Abs(&buy.Units.Rat)
 | 
						units.Abs(&buy.Units.Rat)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: SubAccount,
 | 
							ImportSplitType: models.SubAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -335,10 +335,10 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
		Amount:          units.FloatString(security.Precision),
 | 
							Amount:          units.FloatString(security.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	units.Neg(&units)
 | 
						units.Neg(&units)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: TradingAccount,
 | 
							ImportSplitType: models.TradingAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + buy.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -349,7 +349,7 @@ func (i *OFXImport) GetInvBuyTran(buy *ofxgo.InvBuy, curdef *models.Security, ac
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetIncomeTran(income *ofxgo.Income, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetIncomeTran(income *ofxgo.Income, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&income.InvTran)
 | 
						t := i.GetInvTran(&income.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(income.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(income.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -370,10 +370,10 @@ func (i *OFXImport) GetIncomeTran(income *ofxgo.Income, curdef *models.Security,
 | 
				
			|||||||
		total.Mul(&total, &income.Currency.CurRate.Rat)
 | 
							total.Mul(&total, &income.Currency.CurRate.Rat)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + income.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + income.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -381,10 +381,10 @@ func (i *OFXImport) GetIncomeTran(income *ofxgo.Income, curdef *models.Security,
 | 
				
			|||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	total.Neg(&total)
 | 
						total.Neg(&total)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: IncomeAccount,
 | 
							ImportSplitType: models.IncomeAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + income.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + income.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -395,7 +395,7 @@ func (i *OFXImport) GetIncomeTran(income *ofxgo.Income, curdef *models.Security,
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetInvExpenseTran(expense *ofxgo.InvExpense, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetInvExpenseTran(expense *ofxgo.InvExpense, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&expense.InvTran)
 | 
						t := i.GetInvTran(&expense.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(expense.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(expense.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -415,10 +415,10 @@ func (i *OFXImport) GetInvExpenseTran(expense *ofxgo.InvExpense, curdef *models.
 | 
				
			|||||||
		total.Mul(&total, &expense.Currency.CurRate.Rat)
 | 
							total.Mul(&total, &expense.Currency.CurRate.Rat)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + expense.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + expense.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -426,10 +426,10 @@ func (i *OFXImport) GetInvExpenseTran(expense *ofxgo.InvExpense, curdef *models.
 | 
				
			|||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	total.Neg(&total)
 | 
						total.Neg(&total)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ExpenseAccount,
 | 
							ImportSplitType: models.ExpenseAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + expense.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + expense.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -440,7 +440,7 @@ func (i *OFXImport) GetInvExpenseTran(expense *ofxgo.InvExpense, curdef *models.
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetMarginInterestTran(marginint *ofxgo.MarginInterest, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetMarginInterestTran(marginint *ofxgo.MarginInterest, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&marginint.InvTran)
 | 
						t := i.GetInvTran(&marginint.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memo := string(marginint.InvTran.Memo)
 | 
						memo := string(marginint.InvTran.Memo)
 | 
				
			||||||
@@ -454,10 +454,10 @@ func (i *OFXImport) GetMarginInterestTran(marginint *ofxgo.MarginInterest, curde
 | 
				
			|||||||
		total.Mul(&total, &marginint.Currency.CurRate.Rat)
 | 
							total.Mul(&total, &marginint.Currency.CurRate.Rat)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + marginint.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + marginint.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -465,10 +465,10 @@ func (i *OFXImport) GetMarginInterestTran(marginint *ofxgo.MarginInterest, curde
 | 
				
			|||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	total.Neg(&total)
 | 
						total.Neg(&total)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: IncomeAccount,
 | 
							ImportSplitType: models.IncomeAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + marginint.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + marginint.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -479,7 +479,7 @@ func (i *OFXImport) GetMarginInterestTran(marginint *ofxgo.MarginInterest, curde
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&reinvest.InvTran)
 | 
						t := i.GetInvTran(&reinvest.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(reinvest.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(reinvest.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -518,10 +518,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if num := commission.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := commission.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Commission,
 | 
								ImportSplitType: models.Commission,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -530,10 +530,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := taxes.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := taxes.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Taxes,
 | 
								ImportSplitType: models.Taxes,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -542,10 +542,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := fees.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := fees.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Fees,
 | 
								ImportSplitType: models.Fees,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -554,10 +554,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := load.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := load.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Load,
 | 
								ImportSplitType: models.Load,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -565,10 +565,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
			Amount:          load.FloatString(curdef.Precision),
 | 
								Amount:          load.FloatString(curdef.Precision),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -576,10 +576,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: IncomeAccount,
 | 
							ImportSplitType: models.IncomeAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -587,20 +587,20 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	total.Neg(&total)
 | 
						total.Neg(&total)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
		Memo:            memo,
 | 
							Memo:            memo,
 | 
				
			||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: TradingAccount,
 | 
							ImportSplitType: models.TradingAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -610,10 +610,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var units big.Rat
 | 
						var units big.Rat
 | 
				
			||||||
	units.Abs(&reinvest.Units.Rat)
 | 
						units.Abs(&reinvest.Units.Rat)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: SubAccount,
 | 
							ImportSplitType: models.SubAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -621,10 +621,10 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
		Amount:          units.FloatString(security.Precision),
 | 
							Amount:          units.FloatString(security.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	units.Neg(&units)
 | 
						units.Neg(&units)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: TradingAccount,
 | 
							ImportSplitType: models.TradingAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + reinvest.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -635,7 +635,7 @@ func (i *OFXImport) GetReinvestTran(reinvest *ofxgo.Reinvest, curdef *models.Sec
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetRetOfCapTran(retofcap *ofxgo.RetOfCap, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetRetOfCapTran(retofcap *ofxgo.RetOfCap, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&retofcap.InvTran)
 | 
						t := i.GetInvTran(&retofcap.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(retofcap.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(retofcap.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -655,10 +655,10 @@ func (i *OFXImport) GetRetOfCapTran(retofcap *ofxgo.RetOfCap, curdef *models.Sec
 | 
				
			|||||||
		total.Mul(&total, &retofcap.Currency.CurRate.Rat)
 | 
							total.Mul(&total, &retofcap.Currency.CurRate.Rat)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + retofcap.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + retofcap.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -666,10 +666,10 @@ func (i *OFXImport) GetRetOfCapTran(retofcap *ofxgo.RetOfCap, curdef *models.Sec
 | 
				
			|||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	total.Neg(&total)
 | 
						total.Neg(&total)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: IncomeAccount,
 | 
							ImportSplitType: models.IncomeAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + retofcap.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + retofcap.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -680,7 +680,7 @@ func (i *OFXImport) GetRetOfCapTran(retofcap *ofxgo.RetOfCap, curdef *models.Sec
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&sell.InvTran)
 | 
						t := i.GetInvTran(&sell.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(sell.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(sell.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -722,10 +722,10 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if num := commission.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := commission.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Commission,
 | 
								ImportSplitType: models.Commission,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -734,10 +734,10 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := taxes.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := taxes.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Taxes,
 | 
								ImportSplitType: models.Taxes,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -746,10 +746,10 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := fees.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := fees.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Fees,
 | 
								ImportSplitType: models.Fees,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -758,10 +758,10 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if num := load.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
						if num := load.Num(); !num.IsInt64() || num.Int64() != 0 {
 | 
				
			||||||
		t.Splits = append(t.Splits, &Split{
 | 
							t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
			// TODO ReversalFiTID?
 | 
								// TODO ReversalFiTID?
 | 
				
			||||||
			Status:          Imported,
 | 
								Status:          models.Imported,
 | 
				
			||||||
			ImportSplitType: Load,
 | 
								ImportSplitType: models.Load,
 | 
				
			||||||
			AccountId:       -1,
 | 
								AccountId:       -1,
 | 
				
			||||||
			SecurityId:      curdef.SecurityId,
 | 
								SecurityId:      curdef.SecurityId,
 | 
				
			||||||
			RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
								RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -769,20 +769,20 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
			Amount:          load.FloatString(curdef.Precision),
 | 
								Amount:          load.FloatString(curdef.Precision),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ImportAccount,
 | 
							ImportSplitType: models.ImportAccount,
 | 
				
			||||||
		AccountId:       account.AccountId,
 | 
							AccountId:       account.AccountId,
 | 
				
			||||||
		SecurityId:      -1,
 | 
							SecurityId:      -1,
 | 
				
			||||||
		RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
		Memo:            memo,
 | 
							Memo:            memo,
 | 
				
			||||||
		Amount:          total.FloatString(curdef.Precision),
 | 
							Amount:          total.FloatString(curdef.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: TradingAccount,
 | 
							ImportSplitType: models.TradingAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      curdef.SecurityId,
 | 
							SecurityId:      curdef.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -792,10 +792,10 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var units big.Rat
 | 
						var units big.Rat
 | 
				
			||||||
	units.Abs(&sell.Units.Rat)
 | 
						units.Abs(&sell.Units.Rat)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: TradingAccount,
 | 
							ImportSplitType: models.TradingAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -803,10 +803,10 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
		Amount:          units.FloatString(security.Precision),
 | 
							Amount:          units.FloatString(security.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	units.Neg(&units)
 | 
						units.Neg(&units)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: SubAccount,
 | 
							ImportSplitType: models.SubAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + sell.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -817,7 +817,7 @@ func (i *OFXImport) GetInvSellTran(sell *ofxgo.InvSell, curdef *models.Security,
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) GetTransferTran(transfer *ofxgo.Transfer, account *Account) (*Transaction, error) {
 | 
					func (i *OFXImport) GetTransferTran(transfer *ofxgo.Transfer, account *models.Account) (*models.Transaction, error) {
 | 
				
			||||||
	t := i.GetInvTran(&transfer.InvTran)
 | 
						t := i.GetInvTran(&transfer.InvTran)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security, err := i.GetSecurityAlternateId(string(transfer.SecID.UniqueID), models.Stock)
 | 
						security, err := i.GetSecurityAlternateId(string(transfer.SecID.UniqueID), models.Stock)
 | 
				
			||||||
@@ -834,10 +834,10 @@ func (i *OFXImport) GetTransferTran(transfer *ofxgo.Transfer, account *Account)
 | 
				
			|||||||
		units.Neg(&transfer.Units.Rat)
 | 
							units.Neg(&transfer.Units.Rat)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: SubAccount,
 | 
							ImportSplitType: models.SubAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + transfer.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + transfer.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -845,10 +845,10 @@ func (i *OFXImport) GetTransferTran(transfer *ofxgo.Transfer, account *Account)
 | 
				
			|||||||
		Amount:          units.FloatString(security.Precision),
 | 
							Amount:          units.FloatString(security.Precision),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	units.Neg(&units)
 | 
						units.Neg(&units)
 | 
				
			||||||
	t.Splits = append(t.Splits, &Split{
 | 
						t.Splits = append(t.Splits, &models.Split{
 | 
				
			||||||
		// TODO ReversalFiTID?
 | 
							// TODO ReversalFiTID?
 | 
				
			||||||
		Status:          Imported,
 | 
							Status:          models.Imported,
 | 
				
			||||||
		ImportSplitType: ExternalAccount,
 | 
							ImportSplitType: models.ExternalAccount,
 | 
				
			||||||
		AccountId:       -1,
 | 
							AccountId:       -1,
 | 
				
			||||||
		SecurityId:      security.SecurityId,
 | 
							SecurityId:      security.SecurityId,
 | 
				
			||||||
		RemoteId:        "ofx:" + transfer.InvTran.FiTID.String(),
 | 
							RemoteId:        "ofx:" + transfer.InvTran.FiTID.String(),
 | 
				
			||||||
@@ -859,12 +859,12 @@ func (i *OFXImport) GetTransferTran(transfer *ofxgo.Transfer, account *Account)
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (i *OFXImport) AddInvTransaction(invtran *ofxgo.InvTransaction, account *Account, curdef *models.Security) error {
 | 
					func (i *OFXImport) AddInvTransaction(invtran *ofxgo.InvTransaction, account *models.Account, curdef *models.Security) error {
 | 
				
			||||||
	if curdef.SecurityId < 1 || curdef.SecurityId > int64(len(i.Securities)) {
 | 
						if curdef.SecurityId < 1 || curdef.SecurityId > int64(len(i.Securities)) {
 | 
				
			||||||
		return errors.New("Internal error: security index not found in OFX import\n")
 | 
							return errors.New("Internal error: security index not found in OFX import\n")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var t *Transaction
 | 
						var t *models.Transaction
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	if tran, ok := (*invtran).(ofxgo.BuyDebt); ok {
 | 
						if tran, ok := (*invtran).(ofxgo.BuyDebt); ok {
 | 
				
			||||||
		t, err = i.GetInvBuyTran(&tran.InvBuy, curdef, account)
 | 
							t, err = i.GetInvBuyTran(&tran.InvBuy, curdef, account)
 | 
				
			||||||
@@ -926,12 +926,12 @@ func (i *OFXImport) importOFXInv(stmt *ofxgo.InvStatementResponse) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	account := Account{
 | 
						account := models.Account{
 | 
				
			||||||
		AccountId:         int64(len(i.Accounts) + 1),
 | 
							AccountId:         int64(len(i.Accounts) + 1),
 | 
				
			||||||
		ExternalAccountId: stmt.InvAcctFrom.AcctID.String(),
 | 
							ExternalAccountId: stmt.InvAcctFrom.AcctID.String(),
 | 
				
			||||||
		SecurityId:        security.SecurityId,
 | 
							SecurityId:        security.SecurityId,
 | 
				
			||||||
		ParentAccountId:   -1,
 | 
							ParentAccountId:   -1,
 | 
				
			||||||
		Type:              Investment,
 | 
							Type:              models.Investment,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i.Accounts = append(i.Accounts, account)
 | 
						i.Accounts = append(i.Accounts, account)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ package handlers_test
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/handlers"
 | 
					 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/models"
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -77,7 +76,7 @@ func findSecurity(client *http.Client, symbol string, tipe models.SecurityType)
 | 
				
			|||||||
	return nil, fmt.Errorf("Unable to find security: \"%s\"", symbol)
 | 
						return nil, fmt.Errorf("Unable to find security: \"%s\"", symbol)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func findAccount(client *http.Client, name string, tipe handlers.AccountType, securityid int64) (*handlers.Account, error) {
 | 
					func findAccount(client *http.Client, name string, tipe models.AccountType, securityid int64) (*models.Account, error) {
 | 
				
			||||||
	accounts, err := getAccounts(client)
 | 
						accounts, err := getAccounts(client)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -105,11 +104,11 @@ func TestImportOFX401kMutualFunds(t *testing.T) {
 | 
				
			|||||||
			t.Fatalf("Error removing default security: %s\n", err)
 | 
								t.Fatalf("Error removing default security: %s\n", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		account := &handlers.Account{
 | 
							account := &models.Account{
 | 
				
			||||||
			SecurityId:      d.securities[0].SecurityId,
 | 
								SecurityId:      d.securities[0].SecurityId,
 | 
				
			||||||
			UserId:          d.users[0].UserId,
 | 
								UserId:          d.users[0].UserId,
 | 
				
			||||||
			ParentAccountId: -1,
 | 
								ParentAccountId: -1,
 | 
				
			||||||
			Type:            handlers.Investment,
 | 
								Type:            models.Investment,
 | 
				
			||||||
			Name:            "401k",
 | 
								Name:            "401k",
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,14 +129,14 @@ func TestImportOFX401kMutualFunds(t *testing.T) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("Error finding VANGUARD TARGET 2045 security: %s\n", err)
 | 
								t.Fatalf("Error finding VANGUARD TARGET 2045 security: %s\n", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		tradingaccount, err := findAccount(d.clients[0], "VANGUARD TARGET 2045", handlers.Trading, security.SecurityId)
 | 
							tradingaccount, err := findAccount(d.clients[0], "VANGUARD TARGET 2045", models.Trading, security.SecurityId)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("Error finding VANGUARD TARGET 2045 trading account: %s\n", err)
 | 
								t.Fatalf("Error finding VANGUARD TARGET 2045 trading account: %s\n", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		accountBalanceHelper(t, d.clients[0], tradingaccount, "-3.35400")
 | 
							accountBalanceHelper(t, d.clients[0], tradingaccount, "-3.35400")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Ensure actual holding account was created and in the correct place
 | 
							// Ensure actual holding account was created and in the correct place
 | 
				
			||||||
		investmentaccount, err := findAccount(d.clients[0], "VANGUARD TARGET 2045", handlers.Investment, security.SecurityId)
 | 
							investmentaccount, err := findAccount(d.clients[0], "VANGUARD TARGET 2045", models.Investment, security.SecurityId)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("Error finding VANGUARD TARGET 2045 investment account: %s\n", err)
 | 
								t.Fatalf("Error finding VANGUARD TARGET 2045 investment account: %s\n", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -164,11 +163,11 @@ func TestImportOFXBrokerage(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Create the brokerage account
 | 
							// Create the brokerage account
 | 
				
			||||||
		account := &handlers.Account{
 | 
							account := &models.Account{
 | 
				
			||||||
			SecurityId:      d.securities[0].SecurityId,
 | 
								SecurityId:      d.securities[0].SecurityId,
 | 
				
			||||||
			UserId:          d.users[0].UserId,
 | 
								UserId:          d.users[0].UserId,
 | 
				
			||||||
			ParentAccountId: -1,
 | 
								ParentAccountId: -1,
 | 
				
			||||||
			Type:            handlers.Investment,
 | 
								Type:            models.Investment,
 | 
				
			||||||
			Name:            "Personal Brokerage",
 | 
								Name:            "Personal Brokerage",
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -185,7 +184,7 @@ func TestImportOFXBrokerage(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Make sure the USD trading account was created and has  the right
 | 
							// Make sure the USD trading account was created and has  the right
 | 
				
			||||||
		// value
 | 
							// value
 | 
				
			||||||
		usdtrading, err := findAccount(d.clients[0], "USD", handlers.Trading, d.users[0].DefaultCurrency)
 | 
							usdtrading, err := findAccount(d.clients[0], "USD", models.Trading, d.users[0].DefaultCurrency)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("Error finding USD trading account: %s\n", err)
 | 
								t.Fatalf("Error finding USD trading account: %s\n", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -210,14 +209,14 @@ func TestImportOFXBrokerage(t *testing.T) {
 | 
				
			|||||||
				t.Fatalf("Error finding security: %s\n", err)
 | 
									t.Fatalf("Error finding security: %s\n", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			account, err := findAccount(d.clients[0], check.Name, handlers.Investment, security.SecurityId)
 | 
								account, err := findAccount(d.clients[0], check.Name, models.Investment, security.SecurityId)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Fatalf("Error finding trading account: %s\n", err)
 | 
									t.Fatalf("Error finding trading account: %s\n", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			accountBalanceHelper(t, d.clients[0], account, check.Balance)
 | 
								accountBalanceHelper(t, d.clients[0], account, check.Balance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			tradingaccount, err := findAccount(d.clients[0], check.Name, handlers.Trading, security.SecurityId)
 | 
								tradingaccount, err := findAccount(d.clients[0], check.Name, models.Trading, security.SecurityId)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Fatalf("Error finding trading account: %s\n", err)
 | 
									t.Fatalf("Error finding trading account: %s\n", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package handlers
 | 
					package handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"github.com/yuin/gopher-lua"
 | 
						"github.com/yuin/gopher-lua"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,7 +60,7 @@ func luaPrice__index(L *lua.LState) int {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		L.Push(SecurityToLua(L, c))
 | 
							L.Push(SecurityToLua(L, c))
 | 
				
			||||||
	case "Value", "value":
 | 
						case "Value", "value":
 | 
				
			||||||
		amt, err := GetBigAmount(p.Value)
 | 
							amt, err := models.GetBigAmount(p.Value)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			panic(err)
 | 
								panic(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,8 +39,8 @@ type TestData struct {
 | 
				
			|||||||
	clients      []*http.Client
 | 
						clients      []*http.Client
 | 
				
			||||||
	securities   []models.Security
 | 
						securities   []models.Security
 | 
				
			||||||
	prices       []handlers.Price
 | 
						prices       []handlers.Price
 | 
				
			||||||
	accounts     []handlers.Account // accounts must appear after their parents in this slice
 | 
						accounts     []models.Account // accounts must appear after their parents in this slice
 | 
				
			||||||
	transactions []handlers.Transaction
 | 
						transactions []models.Transaction
 | 
				
			||||||
	reports      []handlers.Report
 | 
						reports      []handlers.Report
 | 
				
			||||||
	tabulations  []handlers.Tabulation
 | 
						tabulations  []handlers.Tabulation
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -113,7 +113,7 @@ func (t *TestData) Initialize() (*TestData, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, transaction := range t.transactions {
 | 
						for i, transaction := range t.transactions {
 | 
				
			||||||
		transaction.Splits = []*handlers.Split{}
 | 
							transaction.Splits = []*models.Split{}
 | 
				
			||||||
		for _, s := range t.transactions[i].Splits {
 | 
							for _, s := range t.transactions[i].Splits {
 | 
				
			||||||
			// Make a copy of the split since Splits is a slice of pointers so
 | 
								// Make a copy of the split since Splits is a slice of pointers so
 | 
				
			||||||
			// copying the transaction doesn't
 | 
								// copying the transaction doesn't
 | 
				
			||||||
@@ -246,78 +246,78 @@ var data = []TestData{
 | 
				
			|||||||
				RemoteId:   "USDEUR819298714",
 | 
									RemoteId:   "USDEUR819298714",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		accounts: []handlers.Account{
 | 
							accounts: []models.Account{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          0,
 | 
									UserId:          0,
 | 
				
			||||||
				SecurityId:      0,
 | 
									SecurityId:      0,
 | 
				
			||||||
				ParentAccountId: -1,
 | 
									ParentAccountId: -1,
 | 
				
			||||||
				Type:            handlers.Asset,
 | 
									Type:            models.Asset,
 | 
				
			||||||
				Name:            "Assets",
 | 
									Name:            "Assets",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          0,
 | 
									UserId:          0,
 | 
				
			||||||
				SecurityId:      0,
 | 
									SecurityId:      0,
 | 
				
			||||||
				ParentAccountId: 0,
 | 
									ParentAccountId: 0,
 | 
				
			||||||
				Type:            handlers.Bank,
 | 
									Type:            models.Bank,
 | 
				
			||||||
				Name:            "Credit Union Checking",
 | 
									Name:            "Credit Union Checking",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          0,
 | 
									UserId:          0,
 | 
				
			||||||
				SecurityId:      0,
 | 
									SecurityId:      0,
 | 
				
			||||||
				ParentAccountId: -1,
 | 
									ParentAccountId: -1,
 | 
				
			||||||
				Type:            handlers.Expense,
 | 
									Type:            models.Expense,
 | 
				
			||||||
				Name:            "Expenses",
 | 
									Name:            "Expenses",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          0,
 | 
									UserId:          0,
 | 
				
			||||||
				SecurityId:      0,
 | 
									SecurityId:      0,
 | 
				
			||||||
				ParentAccountId: 2,
 | 
									ParentAccountId: 2,
 | 
				
			||||||
				Type:            handlers.Expense,
 | 
									Type:            models.Expense,
 | 
				
			||||||
				Name:            "Groceries",
 | 
									Name:            "Groceries",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          0,
 | 
									UserId:          0,
 | 
				
			||||||
				SecurityId:      0,
 | 
									SecurityId:      0,
 | 
				
			||||||
				ParentAccountId: 2,
 | 
									ParentAccountId: 2,
 | 
				
			||||||
				Type:            handlers.Expense,
 | 
									Type:            models.Expense,
 | 
				
			||||||
				Name:            "Cable",
 | 
									Name:            "Cable",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          1,
 | 
									UserId:          1,
 | 
				
			||||||
				SecurityId:      2,
 | 
									SecurityId:      2,
 | 
				
			||||||
				ParentAccountId: -1,
 | 
									ParentAccountId: -1,
 | 
				
			||||||
				Type:            handlers.Asset,
 | 
									Type:            models.Asset,
 | 
				
			||||||
				Name:            "Assets",
 | 
									Name:            "Assets",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          1,
 | 
									UserId:          1,
 | 
				
			||||||
				SecurityId:      2,
 | 
									SecurityId:      2,
 | 
				
			||||||
				ParentAccountId: -1,
 | 
									ParentAccountId: -1,
 | 
				
			||||||
				Type:            handlers.Expense,
 | 
									Type:            models.Expense,
 | 
				
			||||||
				Name:            "Expenses",
 | 
									Name:            "Expenses",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:          0,
 | 
									UserId:          0,
 | 
				
			||||||
				SecurityId:      0,
 | 
									SecurityId:      0,
 | 
				
			||||||
				ParentAccountId: -1,
 | 
									ParentAccountId: -1,
 | 
				
			||||||
				Type:            handlers.Liability,
 | 
									Type:            models.Liability,
 | 
				
			||||||
				Name:            "Credit Card",
 | 
									Name:            "Credit Card",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		transactions: []handlers.Transaction{
 | 
							transactions: []models.Transaction{
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				UserId:      0,
 | 
									UserId:      0,
 | 
				
			||||||
				Description: "weekly groceries",
 | 
									Description: "weekly groceries",
 | 
				
			||||||
				Date:        time.Date(2017, time.October, 15, 1, 16, 59, 0, time.UTC),
 | 
									Date:        time.Date(2017, time.October, 15, 1, 16, 59, 0, time.UTC),
 | 
				
			||||||
				Splits: []*handlers.Split{
 | 
									Splits: []*models.Split{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Reconciled,
 | 
											Status:     models.Reconciled,
 | 
				
			||||||
						AccountId:  1,
 | 
											AccountId:  1,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "-5.6",
 | 
											Amount:     "-5.6",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Reconciled,
 | 
											Status:     models.Reconciled,
 | 
				
			||||||
						AccountId:  3,
 | 
											AccountId:  3,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "5.6",
 | 
											Amount:     "5.6",
 | 
				
			||||||
@@ -328,15 +328,15 @@ var data = []TestData{
 | 
				
			|||||||
				UserId:      0,
 | 
									UserId:      0,
 | 
				
			||||||
				Description: "weekly groceries",
 | 
									Description: "weekly groceries",
 | 
				
			||||||
				Date:        time.Date(2017, time.October, 31, 19, 10, 14, 0, time.UTC),
 | 
									Date:        time.Date(2017, time.October, 31, 19, 10, 14, 0, time.UTC),
 | 
				
			||||||
				Splits: []*handlers.Split{
 | 
									Splits: []*models.Split{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Reconciled,
 | 
											Status:     models.Reconciled,
 | 
				
			||||||
						AccountId:  1,
 | 
											AccountId:  1,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "-81.59",
 | 
											Amount:     "-81.59",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Reconciled,
 | 
											Status:     models.Reconciled,
 | 
				
			||||||
						AccountId:  3,
 | 
											AccountId:  3,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "81.59",
 | 
											Amount:     "81.59",
 | 
				
			||||||
@@ -347,15 +347,15 @@ var data = []TestData{
 | 
				
			|||||||
				UserId:      0,
 | 
									UserId:      0,
 | 
				
			||||||
				Description: "Cable",
 | 
									Description: "Cable",
 | 
				
			||||||
				Date:        time.Date(2017, time.September, 2, 0, 00, 00, 0, time.UTC),
 | 
									Date:        time.Date(2017, time.September, 2, 0, 00, 00, 0, time.UTC),
 | 
				
			||||||
				Splits: []*handlers.Split{
 | 
									Splits: []*models.Split{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Reconciled,
 | 
											Status:     models.Reconciled,
 | 
				
			||||||
						AccountId:  1,
 | 
											AccountId:  1,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "-39.99",
 | 
											Amount:     "-39.99",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Entered,
 | 
											Status:     models.Entered,
 | 
				
			||||||
						AccountId:  4,
 | 
											AccountId:  4,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "39.99",
 | 
											Amount:     "39.99",
 | 
				
			||||||
@@ -366,15 +366,15 @@ var data = []TestData{
 | 
				
			|||||||
				UserId:      1,
 | 
									UserId:      1,
 | 
				
			||||||
				Description: "Gas",
 | 
									Description: "Gas",
 | 
				
			||||||
				Date:        time.Date(2017, time.November, 1, 13, 19, 50, 0, time.UTC),
 | 
									Date:        time.Date(2017, time.November, 1, 13, 19, 50, 0, time.UTC),
 | 
				
			||||||
				Splits: []*handlers.Split{
 | 
									Splits: []*models.Split{
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Reconciled,
 | 
											Status:     models.Reconciled,
 | 
				
			||||||
						AccountId:  5,
 | 
											AccountId:  5,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "-24.56",
 | 
											Amount:     "-24.56",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Status:     handlers.Entered,
 | 
											Status:     models.Entered,
 | 
				
			||||||
						AccountId:  6,
 | 
											AccountId:  6,
 | 
				
			||||||
						SecurityId: -1,
 | 
											SecurityId: -1,
 | 
				
			||||||
						Amount:     "24.56",
 | 
											Amount:     "24.56",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
package handlers
 | 
					package handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/models"
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
@@ -10,141 +9,17 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Split.Status
 | 
					func SplitAlreadyImported(tx *Tx, s *models.Split) (bool, error) {
 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	Imported   int64 = 1
 | 
					 | 
				
			||||||
	Entered          = 2
 | 
					 | 
				
			||||||
	Cleared          = 3
 | 
					 | 
				
			||||||
	Reconciled       = 4
 | 
					 | 
				
			||||||
	Voided           = 5
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Split.ImportSplitType
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	Default         int64 = 0
 | 
					 | 
				
			||||||
	ImportAccount         = 1 // This split belongs to the main account being imported
 | 
					 | 
				
			||||||
	SubAccount            = 2 // This split belongs to a sub-account of that being imported
 | 
					 | 
				
			||||||
	ExternalAccount       = 3
 | 
					 | 
				
			||||||
	TradingAccount        = 4
 | 
					 | 
				
			||||||
	Commission            = 5
 | 
					 | 
				
			||||||
	Taxes                 = 6
 | 
					 | 
				
			||||||
	Fees                  = 7
 | 
					 | 
				
			||||||
	Load                  = 8
 | 
					 | 
				
			||||||
	IncomeAccount         = 9
 | 
					 | 
				
			||||||
	ExpenseAccount        = 10
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Split struct {
 | 
					 | 
				
			||||||
	SplitId         int64
 | 
					 | 
				
			||||||
	TransactionId   int64
 | 
					 | 
				
			||||||
	Status          int64
 | 
					 | 
				
			||||||
	ImportSplitType int64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// One of AccountId and SecurityId must be -1
 | 
					 | 
				
			||||||
	// In normal splits, AccountId will be valid and SecurityId will be -1. The
 | 
					 | 
				
			||||||
	// only case where this is reversed is for transactions that have been
 | 
					 | 
				
			||||||
	// imported and not yet associated with an account.
 | 
					 | 
				
			||||||
	AccountId  int64
 | 
					 | 
				
			||||||
	SecurityId int64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	RemoteId string // unique ID from server, for detecting duplicates
 | 
					 | 
				
			||||||
	Number   string // Check or reference number
 | 
					 | 
				
			||||||
	Memo     string
 | 
					 | 
				
			||||||
	Amount   string // String representation of decimal, suitable for passing to big.Rat.SetString()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func GetBigAmount(amt string) (*big.Rat, error) {
 | 
					 | 
				
			||||||
	var r big.Rat
 | 
					 | 
				
			||||||
	_, success := r.SetString(amt)
 | 
					 | 
				
			||||||
	if !success {
 | 
					 | 
				
			||||||
		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 {
 | 
					 | 
				
			||||||
	if (s.AccountId == -1) == (s.SecurityId == -1) {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_, err := s.GetAmount()
 | 
					 | 
				
			||||||
	return err == nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *Split) AlreadyImported(tx *Tx) (bool, error) {
 | 
					 | 
				
			||||||
	count, err := tx.SelectInt("SELECT COUNT(*) from splits where RemoteId=? and AccountId=?", s.RemoteId, s.AccountId)
 | 
						count, err := tx.SelectInt("SELECT COUNT(*) from splits where RemoteId=? and AccountId=?", s.RemoteId, s.AccountId)
 | 
				
			||||||
	return count == 1, err
 | 
						return count == 1, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Transaction struct {
 | 
					 | 
				
			||||||
	TransactionId int64
 | 
					 | 
				
			||||||
	UserId        int64
 | 
					 | 
				
			||||||
	Description   string
 | 
					 | 
				
			||||||
	Date          time.Time
 | 
					 | 
				
			||||||
	Splits        []*Split `db:"-"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type TransactionList struct {
 | 
					 | 
				
			||||||
	Transactions *[]Transaction `json:"transactions"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type AccountTransactionsList struct {
 | 
					 | 
				
			||||||
	Account           *Account
 | 
					 | 
				
			||||||
	Transactions      *[]Transaction
 | 
					 | 
				
			||||||
	TotalTransactions int64
 | 
					 | 
				
			||||||
	BeginningBalance  string
 | 
					 | 
				
			||||||
	EndingBalance     string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (t *Transaction) Write(w http.ResponseWriter) error {
 | 
					 | 
				
			||||||
	enc := json.NewEncoder(w)
 | 
					 | 
				
			||||||
	return enc.Encode(t)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (t *Transaction) Read(json_str string) error {
 | 
					 | 
				
			||||||
	dec := json.NewDecoder(strings.NewReader(json_str))
 | 
					 | 
				
			||||||
	return dec.Decode(t)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (tl *TransactionList) Write(w http.ResponseWriter) error {
 | 
					 | 
				
			||||||
	enc := json.NewEncoder(w)
 | 
					 | 
				
			||||||
	return enc.Encode(tl)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (tl *TransactionList) Read(json_str string) error {
 | 
					 | 
				
			||||||
	dec := json.NewDecoder(strings.NewReader(json_str))
 | 
					 | 
				
			||||||
	return dec.Decode(tl)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (atl *AccountTransactionsList) Write(w http.ResponseWriter) error {
 | 
					 | 
				
			||||||
	enc := json.NewEncoder(w)
 | 
					 | 
				
			||||||
	return enc.Encode(atl)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (atl *AccountTransactionsList) Read(json_str string) error {
 | 
					 | 
				
			||||||
	dec := json.NewDecoder(strings.NewReader(json_str))
 | 
					 | 
				
			||||||
	return dec.Decode(atl)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (t *Transaction) Valid() bool {
 | 
					 | 
				
			||||||
	for i := range t.Splits {
 | 
					 | 
				
			||||||
		if !t.Splits[i].Valid() {
 | 
					 | 
				
			||||||
			return false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Return a map of security ID's to big.Rat's containing the amount that
 | 
					// Return a map of security ID's to big.Rat's containing the amount that
 | 
				
			||||||
// security is imbalanced by
 | 
					// security is imbalanced by
 | 
				
			||||||
func (t *Transaction) GetImbalances(tx *Tx) (map[int64]big.Rat, error) {
 | 
					func GetTransactionImbalances(tx *Tx, t *models.Transaction) (map[int64]big.Rat, error) {
 | 
				
			||||||
	sums := make(map[int64]big.Rat)
 | 
						sums := make(map[int64]big.Rat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !t.Valid() {
 | 
						if !t.Valid() {
 | 
				
			||||||
@@ -155,7 +30,7 @@ func (t *Transaction) GetImbalances(tx *Tx) (map[int64]big.Rat, error) {
 | 
				
			|||||||
		securityid := t.Splits[i].SecurityId
 | 
							securityid := t.Splits[i].SecurityId
 | 
				
			||||||
		if t.Splits[i].AccountId != -1 {
 | 
							if t.Splits[i].AccountId != -1 {
 | 
				
			||||||
			var err error
 | 
								var err error
 | 
				
			||||||
			var account *Account
 | 
								var account *models.Account
 | 
				
			||||||
			account, err = GetAccount(tx, t.Splits[i].AccountId, t.UserId)
 | 
								account, err = GetAccount(tx, t.Splits[i].AccountId, t.UserId)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, err
 | 
									return nil, err
 | 
				
			||||||
@@ -172,10 +47,10 @@ func (t *Transaction) GetImbalances(tx *Tx) (map[int64]big.Rat, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Returns true if all securities contained in this transaction are balanced,
 | 
					// Returns true if all securities contained in this transaction are balanced,
 | 
				
			||||||
// false otherwise
 | 
					// false otherwise
 | 
				
			||||||
func (t *Transaction) Balanced(tx *Tx) (bool, error) {
 | 
					func TransactionBalanced(tx *Tx, t *models.Transaction) (bool, error) {
 | 
				
			||||||
	var zero big.Rat
 | 
						var zero big.Rat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sums, err := t.GetImbalances(tx)
 | 
						sums, err := GetTransactionImbalances(tx, t)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false, err
 | 
							return false, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -188,8 +63,8 @@ func (t *Transaction) Balanced(tx *Tx) (bool, error) {
 | 
				
			|||||||
	return true, nil
 | 
						return true, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetTransaction(tx *Tx, transactionid int64, userid int64) (*Transaction, error) {
 | 
					func GetTransaction(tx *Tx, transactionid int64, userid int64) (*models.Transaction, error) {
 | 
				
			||||||
	var t Transaction
 | 
						var t models.Transaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := tx.SelectOne(&t, "SELECT * from transactions where UserId=? AND TransactionId=?", userid, transactionid)
 | 
						err := tx.SelectOne(&t, "SELECT * from transactions where UserId=? AND TransactionId=?", userid, transactionid)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -204,8 +79,8 @@ func GetTransaction(tx *Tx, transactionid int64, userid int64) (*Transaction, er
 | 
				
			|||||||
	return &t, nil
 | 
						return &t, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetTransactions(tx *Tx, userid int64) (*[]Transaction, error) {
 | 
					func GetTransactions(tx *Tx, userid int64) (*[]models.Transaction, error) {
 | 
				
			||||||
	var transactions []Transaction
 | 
						var transactions []models.Transaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := tx.Select(&transactions, "SELECT * from transactions where UserId=?", userid)
 | 
						_, err := tx.Select(&transactions, "SELECT * from transactions where UserId=?", userid)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -246,7 +121,7 @@ func (ame AccountMissingError) Error() string {
 | 
				
			|||||||
	return "Account missing"
 | 
						return "Account missing"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func InsertTransaction(tx *Tx, t *Transaction, user *models.User) error {
 | 
					func InsertTransaction(tx *Tx, t *models.Transaction, user *models.User) error {
 | 
				
			||||||
	// Map of any accounts with transaction splits being added
 | 
						// Map of any accounts with transaction splits being added
 | 
				
			||||||
	a_map := make(map[int64]bool)
 | 
						a_map := make(map[int64]bool)
 | 
				
			||||||
	for i := range t.Splits {
 | 
						for i := range t.Splits {
 | 
				
			||||||
@@ -296,8 +171,8 @@ func InsertTransaction(tx *Tx, t *Transaction, user *models.User) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func UpdateTransaction(tx *Tx, t *Transaction, user *models.User) error {
 | 
					func UpdateTransaction(tx *Tx, t *models.Transaction, user *models.User) error {
 | 
				
			||||||
	var existing_splits []*Split
 | 
						var existing_splits []*models.Split
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := tx.Select(&existing_splits, "SELECT * from splits where TransactionId=?", t.TransactionId)
 | 
						_, err := tx.Select(&existing_splits, "SELECT * from splits where TransactionId=?", t.TransactionId)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -373,7 +248,7 @@ func UpdateTransaction(tx *Tx, t *Transaction, user *models.User) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DeleteTransaction(tx *Tx, t *Transaction, user *models.User) error {
 | 
					func DeleteTransaction(tx *Tx, t *models.Transaction, user *models.User) error {
 | 
				
			||||||
	var accountids []int64
 | 
						var accountids []int64
 | 
				
			||||||
	_, err := tx.Select(&accountids, "SELECT DISTINCT AccountId FROM splits WHERE TransactionId=? AND AccountId != -1", t.TransactionId)
 | 
						_, err := tx.Select(&accountids, "SELECT DISTINCT AccountId FROM splits WHERE TransactionId=? AND AccountId != -1", t.TransactionId)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -408,7 +283,7 @@ func TransactionHandler(r *http.Request, context *Context) ResponseWriterWriter
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if r.Method == "POST" {
 | 
						if r.Method == "POST" {
 | 
				
			||||||
		var transaction Transaction
 | 
							var transaction models.Transaction
 | 
				
			||||||
		if err := ReadJSON(r, &transaction); err != nil {
 | 
							if err := ReadJSON(r, &transaction); err != nil {
 | 
				
			||||||
			return NewError(3 /*Invalid Request*/)
 | 
								return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -427,7 +302,7 @@ func TransactionHandler(r *http.Request, context *Context) ResponseWriterWriter
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		balanced, err := transaction.Balanced(context.Tx)
 | 
							balanced, err := TransactionBalanced(context.Tx, &transaction)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return NewError(999 /*Internal Error*/)
 | 
								return NewError(999 /*Internal Error*/)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -449,7 +324,7 @@ func TransactionHandler(r *http.Request, context *Context) ResponseWriterWriter
 | 
				
			|||||||
	} else if r.Method == "GET" {
 | 
						} else if r.Method == "GET" {
 | 
				
			||||||
		if context.LastLevel() {
 | 
							if context.LastLevel() {
 | 
				
			||||||
			//Return all Transactions
 | 
								//Return all Transactions
 | 
				
			||||||
			var al TransactionList
 | 
								var al models.TransactionList
 | 
				
			||||||
			transactions, err := GetTransactions(context.Tx, user.UserId)
 | 
								transactions, err := GetTransactions(context.Tx, user.UserId)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Print(err)
 | 
									log.Print(err)
 | 
				
			||||||
@@ -475,13 +350,13 @@ func TransactionHandler(r *http.Request, context *Context) ResponseWriterWriter
 | 
				
			|||||||
			return NewError(3 /*Invalid Request*/)
 | 
								return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if r.Method == "PUT" {
 | 
							if r.Method == "PUT" {
 | 
				
			||||||
			var transaction Transaction
 | 
								var transaction models.Transaction
 | 
				
			||||||
			if err := ReadJSON(r, &transaction); err != nil || transaction.TransactionId != transactionid {
 | 
								if err := ReadJSON(r, &transaction); err != nil || transaction.TransactionId != transactionid {
 | 
				
			||||||
				return NewError(3 /*Invalid Request*/)
 | 
									return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			transaction.UserId = user.UserId
 | 
								transaction.UserId = user.UserId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			balanced, err := transaction.Balanced(context.Tx)
 | 
								balanced, err := TransactionBalanced(context.Tx, &transaction)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Print(err)
 | 
									log.Print(err)
 | 
				
			||||||
				return NewError(999 /*Internal Error*/)
 | 
									return NewError(999 /*Internal Error*/)
 | 
				
			||||||
@@ -526,7 +401,7 @@ func TransactionHandler(r *http.Request, context *Context) ResponseWriterWriter
 | 
				
			|||||||
	return NewError(3 /*Invalid Request*/)
 | 
						return NewError(3 /*Invalid Request*/)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TransactionsBalanceDifference(tx *Tx, accountid int64, transactions []Transaction) (*big.Rat, error) {
 | 
					func TransactionsBalanceDifference(tx *Tx, accountid int64, transactions []models.Transaction) (*big.Rat, error) {
 | 
				
			||||||
	var pageDifference, tmp big.Rat
 | 
						var pageDifference, tmp big.Rat
 | 
				
			||||||
	for i := range transactions {
 | 
						for i := range transactions {
 | 
				
			||||||
		_, err := tx.Select(&transactions[i].Splits, "SELECT * FROM splits where TransactionId=?", transactions[i].TransactionId)
 | 
							_, err := tx.Select(&transactions[i].Splits, "SELECT * FROM splits where TransactionId=?", transactions[i].TransactionId)
 | 
				
			||||||
@@ -538,7 +413,7 @@ func TransactionsBalanceDifference(tx *Tx, accountid int64, transactions []Trans
 | 
				
			|||||||
		// an ending balance
 | 
							// an ending balance
 | 
				
			||||||
		for j := range transactions[i].Splits {
 | 
							for j := range transactions[i].Splits {
 | 
				
			||||||
			if transactions[i].Splits[j].AccountId == accountid {
 | 
								if transactions[i].Splits[j].AccountId == accountid {
 | 
				
			||||||
				rat_amount, err := GetBigAmount(transactions[i].Splits[j].Amount)
 | 
									rat_amount, err := models.GetBigAmount(transactions[i].Splits[j].Amount)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return nil, err
 | 
										return nil, err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -551,7 +426,7 @@ func TransactionsBalanceDifference(tx *Tx, accountid int64, transactions []Trans
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetAccountBalance(tx *Tx, user *models.User, accountid int64) (*big.Rat, error) {
 | 
					func GetAccountBalance(tx *Tx, user *models.User, accountid int64) (*big.Rat, error) {
 | 
				
			||||||
	var splits []Split
 | 
						var splits []models.Split
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=?"
 | 
						sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=?"
 | 
				
			||||||
	_, err := tx.Select(&splits, sql, accountid, user.UserId)
 | 
						_, err := tx.Select(&splits, sql, accountid, user.UserId)
 | 
				
			||||||
@@ -561,7 +436,7 @@ func GetAccountBalance(tx *Tx, user *models.User, accountid int64) (*big.Rat, er
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var balance, tmp big.Rat
 | 
						var balance, tmp big.Rat
 | 
				
			||||||
	for _, s := range splits {
 | 
						for _, s := range splits {
 | 
				
			||||||
		rat_amount, err := GetBigAmount(s.Amount)
 | 
							rat_amount, err := models.GetBigAmount(s.Amount)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -574,7 +449,7 @@ func GetAccountBalance(tx *Tx, user *models.User, accountid int64) (*big.Rat, er
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Assumes accountid is valid and is owned by the current user
 | 
					// Assumes accountid is valid and is owned by the current user
 | 
				
			||||||
func GetAccountBalanceDate(tx *Tx, user *models.User, accountid int64, date *time.Time) (*big.Rat, error) {
 | 
					func GetAccountBalanceDate(tx *Tx, user *models.User, accountid int64, date *time.Time) (*big.Rat, error) {
 | 
				
			||||||
	var splits []Split
 | 
						var splits []models.Split
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=? AND transactions.Date < ?"
 | 
						sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=? AND transactions.Date < ?"
 | 
				
			||||||
	_, err := tx.Select(&splits, sql, accountid, user.UserId, date)
 | 
						_, err := tx.Select(&splits, sql, accountid, user.UserId, date)
 | 
				
			||||||
@@ -584,7 +459,7 @@ func GetAccountBalanceDate(tx *Tx, user *models.User, accountid int64, date *tim
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var balance, tmp big.Rat
 | 
						var balance, tmp big.Rat
 | 
				
			||||||
	for _, s := range splits {
 | 
						for _, s := range splits {
 | 
				
			||||||
		rat_amount, err := GetBigAmount(s.Amount)
 | 
							rat_amount, err := models.GetBigAmount(s.Amount)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -596,7 +471,7 @@ func GetAccountBalanceDate(tx *Tx, user *models.User, accountid int64, date *tim
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetAccountBalanceDateRange(tx *Tx, user *models.User, accountid int64, begin, end *time.Time) (*big.Rat, error) {
 | 
					func GetAccountBalanceDateRange(tx *Tx, user *models.User, accountid int64, begin, end *time.Time) (*big.Rat, error) {
 | 
				
			||||||
	var splits []Split
 | 
						var splits []models.Split
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=? AND transactions.Date >= ? AND transactions.Date < ?"
 | 
						sql := "SELECT DISTINCT splits.* FROM splits INNER JOIN transactions ON transactions.TransactionId = splits.TransactionId WHERE splits.AccountId=? AND transactions.UserId=? AND transactions.Date >= ? AND transactions.Date < ?"
 | 
				
			||||||
	_, err := tx.Select(&splits, sql, accountid, user.UserId, begin, end)
 | 
						_, err := tx.Select(&splits, sql, accountid, user.UserId, begin, end)
 | 
				
			||||||
@@ -606,7 +481,7 @@ func GetAccountBalanceDateRange(tx *Tx, user *models.User, accountid int64, begi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var balance, tmp big.Rat
 | 
						var balance, tmp big.Rat
 | 
				
			||||||
	for _, s := range splits {
 | 
						for _, s := range splits {
 | 
				
			||||||
		rat_amount, err := GetBigAmount(s.Amount)
 | 
							rat_amount, err := models.GetBigAmount(s.Amount)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -617,9 +492,9 @@ func GetAccountBalanceDateRange(tx *Tx, user *models.User, accountid int64, begi
 | 
				
			|||||||
	return &balance, nil
 | 
						return &balance, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetAccountTransactions(tx *Tx, user *models.User, accountid int64, sort string, page uint64, limit uint64) (*AccountTransactionsList, error) {
 | 
					func GetAccountTransactions(tx *Tx, user *models.User, accountid int64, sort string, page uint64, limit uint64) (*models.AccountTransactionsList, error) {
 | 
				
			||||||
	var transactions []Transaction
 | 
						var transactions []models.Transaction
 | 
				
			||||||
	var atl AccountTransactionsList
 | 
						var atl models.AccountTransactionsList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var sqlsort, balanceLimitOffset string
 | 
						var sqlsort, balanceLimitOffset string
 | 
				
			||||||
	var balanceLimitOffsetArg uint64
 | 
						var balanceLimitOffsetArg uint64
 | 
				
			||||||
@@ -685,7 +560,7 @@ func GetAccountTransactions(tx *Tx, user *models.User, accountid int64, sort str
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var tmp, balance big.Rat
 | 
						var tmp, balance big.Rat
 | 
				
			||||||
	for _, amount := range amounts {
 | 
						for _, amount := range amounts {
 | 
				
			||||||
		rat_amount, err := GetBigAmount(amount)
 | 
							rat_amount, err := models.GetBigAmount(amount)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package handlers_test
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/aclindsa/moneygo/internal/handlers"
 | 
						"github.com/aclindsa/moneygo/internal/handlers"
 | 
				
			||||||
 | 
						"github.com/aclindsa/moneygo/internal/models"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -10,14 +11,14 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func createTransaction(client *http.Client, transaction *handlers.Transaction) (*handlers.Transaction, error) {
 | 
					func createTransaction(client *http.Client, transaction *models.Transaction) (*models.Transaction, error) {
 | 
				
			||||||
	var s handlers.Transaction
 | 
						var s models.Transaction
 | 
				
			||||||
	err := create(client, transaction, &s, "/v1/transactions/")
 | 
						err := create(client, transaction, &s, "/v1/transactions/")
 | 
				
			||||||
	return &s, err
 | 
						return &s, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getTransaction(client *http.Client, transactionid int64) (*handlers.Transaction, error) {
 | 
					func getTransaction(client *http.Client, transactionid int64) (*models.Transaction, error) {
 | 
				
			||||||
	var s handlers.Transaction
 | 
						var s models.Transaction
 | 
				
			||||||
	err := read(client, &s, "/v1/transactions/"+strconv.FormatInt(transactionid, 10))
 | 
						err := read(client, &s, "/v1/transactions/"+strconv.FormatInt(transactionid, 10))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -25,8 +26,8 @@ func getTransaction(client *http.Client, transactionid int64) (*handlers.Transac
 | 
				
			|||||||
	return &s, nil
 | 
						return &s, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getTransactions(client *http.Client) (*handlers.TransactionList, error) {
 | 
					func getTransactions(client *http.Client) (*models.TransactionList, error) {
 | 
				
			||||||
	var tl handlers.TransactionList
 | 
						var tl models.TransactionList
 | 
				
			||||||
	err := read(client, &tl, "/v1/transactions/")
 | 
						err := read(client, &tl, "/v1/transactions/")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -34,8 +35,8 @@ func getTransactions(client *http.Client) (*handlers.TransactionList, error) {
 | 
				
			|||||||
	return &tl, nil
 | 
						return &tl, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getAccountTransactions(client *http.Client, accountid, page, limit int64, sort string) (*handlers.AccountTransactionsList, error) {
 | 
					func getAccountTransactions(client *http.Client, accountid, page, limit int64, sort string) (*models.AccountTransactionsList, error) {
 | 
				
			||||||
	var atl handlers.AccountTransactionsList
 | 
						var atl models.AccountTransactionsList
 | 
				
			||||||
	params := url.Values{}
 | 
						params := url.Values{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	query := fmt.Sprintf("/v1/accounts/%d/transactions/", accountid)
 | 
						query := fmt.Sprintf("/v1/accounts/%d/transactions/", accountid)
 | 
				
			||||||
@@ -57,8 +58,8 @@ func getAccountTransactions(client *http.Client, accountid, page, limit int64, s
 | 
				
			|||||||
	return &atl, nil
 | 
						return &atl, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func updateTransaction(client *http.Client, transaction *handlers.Transaction) (*handlers.Transaction, error) {
 | 
					func updateTransaction(client *http.Client, transaction *models.Transaction) (*models.Transaction, error) {
 | 
				
			||||||
	var s handlers.Transaction
 | 
						var s models.Transaction
 | 
				
			||||||
	err := update(client, transaction, &s, "/v1/transactions/"+strconv.FormatInt(transaction.TransactionId, 10))
 | 
						err := update(client, transaction, &s, "/v1/transactions/"+strconv.FormatInt(transaction.TransactionId, 10))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -66,7 +67,7 @@ func updateTransaction(client *http.Client, transaction *handlers.Transaction) (
 | 
				
			|||||||
	return &s, nil
 | 
						return &s, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func deleteTransaction(client *http.Client, s *handlers.Transaction) error {
 | 
					func deleteTransaction(client *http.Client, s *models.Transaction) error {
 | 
				
			||||||
	err := remove(client, "/v1/transactions/"+strconv.FormatInt(s.TransactionId, 10))
 | 
						err := remove(client, "/v1/transactions/"+strconv.FormatInt(s.TransactionId, 10))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -74,7 +75,7 @@ func deleteTransaction(client *http.Client, s *handlers.Transaction) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ensureTransactionsMatch(t *testing.T, expected, tran *handlers.Transaction, accounts *[]handlers.Account, matchtransactionids, matchsplitids bool) {
 | 
					func ensureTransactionsMatch(t *testing.T, expected, tran *models.Transaction, accounts *[]models.Account, matchtransactionids, matchsplitids bool) {
 | 
				
			||||||
	t.Helper()
 | 
						t.Helper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if tran.TransactionId == 0 {
 | 
						if tran.TransactionId == 0 {
 | 
				
			||||||
@@ -136,9 +137,9 @@ func ensureTransactionsMatch(t *testing.T, expected, tran *handlers.Transaction,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getAccountVersionMap(t *testing.T, client *http.Client, tran *handlers.Transaction) map[int64]*handlers.Account {
 | 
					func getAccountVersionMap(t *testing.T, client *http.Client, tran *models.Transaction) map[int64]*models.Account {
 | 
				
			||||||
	t.Helper()
 | 
						t.Helper()
 | 
				
			||||||
	accountMap := make(map[int64]*handlers.Account)
 | 
						accountMap := make(map[int64]*models.Account)
 | 
				
			||||||
	for _, split := range tran.Splits {
 | 
						for _, split := range tran.Splits {
 | 
				
			||||||
		account, err := getAccount(client, split.AccountId)
 | 
							account, err := getAccount(client, split.AccountId)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -149,7 +150,7 @@ func getAccountVersionMap(t *testing.T, client *http.Client, tran *handlers.Tran
 | 
				
			|||||||
	return accountMap
 | 
						return accountMap
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkAccountVersionsUpdated(t *testing.T, client *http.Client, accountMap map[int64]*handlers.Account, tran *handlers.Transaction) {
 | 
					func checkAccountVersionsUpdated(t *testing.T, client *http.Client, accountMap map[int64]*models.Account, tran *models.Transaction) {
 | 
				
			||||||
	for _, split := range tran.Splits {
 | 
						for _, split := range tran.Splits {
 | 
				
			||||||
		account, err := getAccount(client, split.AccountId)
 | 
							account, err := getAccount(client, split.AccountId)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -177,19 +178,19 @@ func TestCreateTransaction(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Don't allow imbalanced transactions
 | 
							// Don't allow imbalanced transactions
 | 
				
			||||||
		tran := handlers.Transaction{
 | 
							tran := models.Transaction{
 | 
				
			||||||
			UserId:      d.users[0].UserId,
 | 
								UserId:      d.users[0].UserId,
 | 
				
			||||||
			Description: "Imbalanced",
 | 
								Description: "Imbalanced",
 | 
				
			||||||
			Date:        time.Date(2017, time.September, 1, 0, 00, 00, 0, time.UTC),
 | 
								Date:        time.Date(2017, time.September, 1, 0, 00, 00, 0, time.UTC),
 | 
				
			||||||
			Splits: []*handlers.Split{
 | 
								Splits: []*models.Split{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Status:     handlers.Reconciled,
 | 
										Status:     models.Reconciled,
 | 
				
			||||||
					AccountId:  d.accounts[1].AccountId,
 | 
										AccountId:  d.accounts[1].AccountId,
 | 
				
			||||||
					SecurityId: -1,
 | 
										SecurityId: -1,
 | 
				
			||||||
					Amount:     "-39.98",
 | 
										Amount:     "-39.98",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Status:     handlers.Entered,
 | 
										Status:     models.Entered,
 | 
				
			||||||
					AccountId:  d.accounts[4].AccountId,
 | 
										AccountId:  d.accounts[4].AccountId,
 | 
				
			||||||
					SecurityId: -1,
 | 
										SecurityId: -1,
 | 
				
			||||||
					Amount:     "39.99",
 | 
										Amount:     "39.99",
 | 
				
			||||||
@@ -209,7 +210,7 @@ func TestCreateTransaction(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Don't allow transactions with 0 splits
 | 
							// Don't allow transactions with 0 splits
 | 
				
			||||||
		tran.Splits = []*handlers.Split{}
 | 
							tran.Splits = []*models.Split{}
 | 
				
			||||||
		_, err = createTransaction(d.clients[0], &tran)
 | 
							_, err = createTransaction(d.clients[0], &tran)
 | 
				
			||||||
		if err == nil {
 | 
							if err == nil {
 | 
				
			||||||
			t.Fatalf("Expected error creating with zero splits")
 | 
								t.Fatalf("Expected error creating with zero splits")
 | 
				
			||||||
@@ -316,9 +317,9 @@ func TestUpdateTransaction(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			ensureTransactionsMatch(t, &curr, tran, nil, true, true)
 | 
								ensureTransactionsMatch(t, &curr, tran, nil, true, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			tran.Splits = []*handlers.Split{}
 | 
								tran.Splits = []*models.Split{}
 | 
				
			||||||
			for _, s := range curr.Splits {
 | 
								for _, s := range curr.Splits {
 | 
				
			||||||
				var split handlers.Split
 | 
									var split models.Split
 | 
				
			||||||
				split = *s
 | 
									split = *s
 | 
				
			||||||
				tran.Splits = append(tran.Splits, &split)
 | 
									tran.Splits = append(tran.Splits, &split)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -346,7 +347,7 @@ func TestUpdateTransaction(t *testing.T) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Don't allow transactions with 0 splits
 | 
								// Don't allow transactions with 0 splits
 | 
				
			||||||
			tran.Splits = []*handlers.Split{}
 | 
								tran.Splits = []*models.Split{}
 | 
				
			||||||
			_, err = updateTransaction(d.clients[orig.UserId], tran)
 | 
								_, err = updateTransaction(d.clients[orig.UserId], tran)
 | 
				
			||||||
			if err == nil {
 | 
								if err == nil {
 | 
				
			||||||
				t.Fatalf("Expected error updating with zero splits")
 | 
									t.Fatalf("Expected error updating with zero splits")
 | 
				
			||||||
@@ -391,12 +392,12 @@ func TestDeleteTransaction(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func helperTestAccountTransactions(t *testing.T, d *TestData, account *handlers.Account, limit int64, sort string) {
 | 
					func helperTestAccountTransactions(t *testing.T, d *TestData, account *models.Account, limit int64, sort string) {
 | 
				
			||||||
	if account.UserId != d.users[0].UserId {
 | 
						if account.UserId != d.users[0].UserId {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var transactions []handlers.Transaction
 | 
						var transactions []models.Transaction
 | 
				
			||||||
	var lastFetchCount int64
 | 
						var lastFetchCount int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for page := int64(0); page == 0 || lastFetchCount > 0; page++ {
 | 
						for page := int64(0); page == 0 || lastFetchCount > 0; page++ {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										118
									
								
								internal/models/accounts.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								internal/models/accounts.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AccountType int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						Bank       AccountType = 1 // start at 1 so that the default (0) is invalid
 | 
				
			||||||
 | 
						Cash                   = 2
 | 
				
			||||||
 | 
						Asset                  = 3
 | 
				
			||||||
 | 
						Liability              = 4
 | 
				
			||||||
 | 
						Investment             = 5
 | 
				
			||||||
 | 
						Income                 = 6
 | 
				
			||||||
 | 
						Expense                = 7
 | 
				
			||||||
 | 
						Trading                = 8
 | 
				
			||||||
 | 
						Equity                 = 9
 | 
				
			||||||
 | 
						Receivable             = 10
 | 
				
			||||||
 | 
						Payable                = 11
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var AccountTypes = []AccountType{
 | 
				
			||||||
 | 
						Bank,
 | 
				
			||||||
 | 
						Cash,
 | 
				
			||||||
 | 
						Asset,
 | 
				
			||||||
 | 
						Liability,
 | 
				
			||||||
 | 
						Investment,
 | 
				
			||||||
 | 
						Income,
 | 
				
			||||||
 | 
						Expense,
 | 
				
			||||||
 | 
						Trading,
 | 
				
			||||||
 | 
						Equity,
 | 
				
			||||||
 | 
						Receivable,
 | 
				
			||||||
 | 
						Payable,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t AccountType) String() string {
 | 
				
			||||||
 | 
						switch t {
 | 
				
			||||||
 | 
						case Bank:
 | 
				
			||||||
 | 
							return "Bank"
 | 
				
			||||||
 | 
						case Cash:
 | 
				
			||||||
 | 
							return "Cash"
 | 
				
			||||||
 | 
						case Asset:
 | 
				
			||||||
 | 
							return "Asset"
 | 
				
			||||||
 | 
						case Liability:
 | 
				
			||||||
 | 
							return "Liability"
 | 
				
			||||||
 | 
						case Investment:
 | 
				
			||||||
 | 
							return "Investment"
 | 
				
			||||||
 | 
						case Income:
 | 
				
			||||||
 | 
							return "Income"
 | 
				
			||||||
 | 
						case Expense:
 | 
				
			||||||
 | 
							return "Expense"
 | 
				
			||||||
 | 
						case Trading:
 | 
				
			||||||
 | 
							return "Trading"
 | 
				
			||||||
 | 
						case Equity:
 | 
				
			||||||
 | 
							return "Equity"
 | 
				
			||||||
 | 
						case Receivable:
 | 
				
			||||||
 | 
							return "Receivable"
 | 
				
			||||||
 | 
						case Payable:
 | 
				
			||||||
 | 
							return "Payable"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Account struct {
 | 
				
			||||||
 | 
						AccountId         int64
 | 
				
			||||||
 | 
						ExternalAccountId string
 | 
				
			||||||
 | 
						UserId            int64
 | 
				
			||||||
 | 
						SecurityId        int64
 | 
				
			||||||
 | 
						ParentAccountId   int64 // -1 if this account is at the root
 | 
				
			||||||
 | 
						Type              AccountType
 | 
				
			||||||
 | 
						Name              string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// monotonically-increasing account transaction version number. Used for
 | 
				
			||||||
 | 
						// allowing a client to ensure they have a consistent version when paging
 | 
				
			||||||
 | 
						// through transactions.
 | 
				
			||||||
 | 
						AccountVersion int64 `json:"Version"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Optional fields specifying how to fetch transactions from a bank via OFX
 | 
				
			||||||
 | 
						OFXURL       string
 | 
				
			||||||
 | 
						OFXORG       string
 | 
				
			||||||
 | 
						OFXFID       string
 | 
				
			||||||
 | 
						OFXUser      string
 | 
				
			||||||
 | 
						OFXBankID    string // OFX BankID (BrokerID if AcctType == Investment)
 | 
				
			||||||
 | 
						OFXAcctID    string
 | 
				
			||||||
 | 
						OFXAcctType  string // ofxgo.acctType
 | 
				
			||||||
 | 
						OFXClientUID string
 | 
				
			||||||
 | 
						OFXAppID     string
 | 
				
			||||||
 | 
						OFXAppVer    string
 | 
				
			||||||
 | 
						OFXVersion   string
 | 
				
			||||||
 | 
						OFXNoIndent  bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AccountList struct {
 | 
				
			||||||
 | 
						Accounts *[]Account `json:"accounts"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a *Account) Write(w http.ResponseWriter) error {
 | 
				
			||||||
 | 
						enc := json.NewEncoder(w)
 | 
				
			||||||
 | 
						return enc.Encode(a)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a *Account) Read(json_str string) error {
 | 
				
			||||||
 | 
						dec := json.NewDecoder(strings.NewReader(json_str))
 | 
				
			||||||
 | 
						return dec.Decode(a)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (al *AccountList) Write(w http.ResponseWriter) error {
 | 
				
			||||||
 | 
						enc := json.NewEncoder(w)
 | 
				
			||||||
 | 
						return enc.Encode(al)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (al *AccountList) Read(json_str string) error {
 | 
				
			||||||
 | 
						dec := json.NewDecoder(strings.NewReader(json_str))
 | 
				
			||||||
 | 
						return dec.Decode(al)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										133
									
								
								internal/models/transactions.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								internal/models/transactions.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Split.Status
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						Imported   int64 = 1
 | 
				
			||||||
 | 
						Entered          = 2
 | 
				
			||||||
 | 
						Cleared          = 3
 | 
				
			||||||
 | 
						Reconciled       = 4
 | 
				
			||||||
 | 
						Voided           = 5
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Split.ImportSplitType
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						Default         int64 = 0
 | 
				
			||||||
 | 
						ImportAccount         = 1 // This split belongs to the main account being imported
 | 
				
			||||||
 | 
						SubAccount            = 2 // This split belongs to a sub-account of that being imported
 | 
				
			||||||
 | 
						ExternalAccount       = 3
 | 
				
			||||||
 | 
						TradingAccount        = 4
 | 
				
			||||||
 | 
						Commission            = 5
 | 
				
			||||||
 | 
						Taxes                 = 6
 | 
				
			||||||
 | 
						Fees                  = 7
 | 
				
			||||||
 | 
						Load                  = 8
 | 
				
			||||||
 | 
						IncomeAccount         = 9
 | 
				
			||||||
 | 
						ExpenseAccount        = 10
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Split struct {
 | 
				
			||||||
 | 
						SplitId         int64
 | 
				
			||||||
 | 
						TransactionId   int64
 | 
				
			||||||
 | 
						Status          int64
 | 
				
			||||||
 | 
						ImportSplitType int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// One of AccountId and SecurityId must be -1
 | 
				
			||||||
 | 
						// In normal splits, AccountId will be valid and SecurityId will be -1. The
 | 
				
			||||||
 | 
						// only case where this is reversed is for transactions that have been
 | 
				
			||||||
 | 
						// imported and not yet associated with an account.
 | 
				
			||||||
 | 
						AccountId  int64
 | 
				
			||||||
 | 
						SecurityId int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoteId string // unique ID from server, for detecting duplicates
 | 
				
			||||||
 | 
						Number   string // Check or reference number
 | 
				
			||||||
 | 
						Memo     string
 | 
				
			||||||
 | 
						Amount   string // String representation of decimal, suitable for passing to big.Rat.SetString()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetBigAmount(amt string) (*big.Rat, error) {
 | 
				
			||||||
 | 
						var r big.Rat
 | 
				
			||||||
 | 
						_, success := r.SetString(amt)
 | 
				
			||||||
 | 
						if !success {
 | 
				
			||||||
 | 
							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 {
 | 
				
			||||||
 | 
						if (s.AccountId == -1) == (s.SecurityId == -1) {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := s.GetAmount()
 | 
				
			||||||
 | 
						return err == nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Transaction struct {
 | 
				
			||||||
 | 
						TransactionId int64
 | 
				
			||||||
 | 
						UserId        int64
 | 
				
			||||||
 | 
						Description   string
 | 
				
			||||||
 | 
						Date          time.Time
 | 
				
			||||||
 | 
						Splits        []*Split `db:"-"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TransactionList struct {
 | 
				
			||||||
 | 
						Transactions *[]Transaction `json:"transactions"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AccountTransactionsList struct {
 | 
				
			||||||
 | 
						Account           *Account
 | 
				
			||||||
 | 
						Transactions      *[]Transaction
 | 
				
			||||||
 | 
						TotalTransactions int64
 | 
				
			||||||
 | 
						BeginningBalance  string
 | 
				
			||||||
 | 
						EndingBalance     string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *Transaction) Write(w http.ResponseWriter) error {
 | 
				
			||||||
 | 
						enc := json.NewEncoder(w)
 | 
				
			||||||
 | 
						return enc.Encode(t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *Transaction) Read(json_str string) error {
 | 
				
			||||||
 | 
						dec := json.NewDecoder(strings.NewReader(json_str))
 | 
				
			||||||
 | 
						return dec.Decode(t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (tl *TransactionList) Write(w http.ResponseWriter) error {
 | 
				
			||||||
 | 
						enc := json.NewEncoder(w)
 | 
				
			||||||
 | 
						return enc.Encode(tl)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (tl *TransactionList) Read(json_str string) error {
 | 
				
			||||||
 | 
						dec := json.NewDecoder(strings.NewReader(json_str))
 | 
				
			||||||
 | 
						return dec.Decode(tl)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (atl *AccountTransactionsList) Write(w http.ResponseWriter) error {
 | 
				
			||||||
 | 
						enc := json.NewEncoder(w)
 | 
				
			||||||
 | 
						return enc.Encode(atl)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (atl *AccountTransactionsList) Read(json_str string) error {
 | 
				
			||||||
 | 
						dec := json.NewDecoder(strings.NewReader(json_str))
 | 
				
			||||||
 | 
						return dec.Decode(atl)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *Transaction) Valid() bool {
 | 
				
			||||||
 | 
						for i := range t.Splits {
 | 
				
			||||||
 | 
							if !t.Splits[i].Valid() {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user