diff --git a/README.md b/README.md index 4b2c97f..5172fe8 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,4 @@ SELECT * FROM accounts where account_id in (select account_id from account_tag w ### TODO - Create Yurnell - programmable journal entries - Add an edit transaction function -- Add MySQL as a database -- test releases from scratch - run GoDBLedger on a separate server and access the open port through the network diff --git a/godbledger/cmd/config.go b/godbledger/cmd/config.go index d269e2f..1142937 100644 --- a/godbledger/cmd/config.go +++ b/godbledger/cmd/config.go @@ -20,7 +20,7 @@ type LedgerConfig struct { LogVerbosity string // LogVerbosity defines the logging level {debug, info, warn, error, fatal, panic} ConfigFile string // Location of the TOML config file, including directory path DatabaseType string // Type of Database being used - DatabaseLocation string // Location of the database file, including directory path + DatabaseLocation string // Location of the database file, including directory path or connection string } var ( @@ -33,6 +33,21 @@ var ( Description: `The dumpconfig command shows configuration values.`, } + InitConfigCommand = &cli.Command{ + Action: initConfig, + Name: "init", + Usage: "godbledger init [-m] [databaseLocation]", + ArgsUsage: "", + Category: "MISCELLANEOUS COMMANDS", + Description: `The init command creates configuration file.`, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "mysql", + Aliases: []string{"m"}, + Usage: "set the database to use mysql rather than sqlite"}, + }, + } + defaultLedgerConfig = &LedgerConfig{ RPCPort: "50051", DataDirectory: DefaultDataDir(), @@ -128,3 +143,34 @@ func dumpConfig(ctx *cli.Context) error { return nil } + +// initConfig is the init command. +func initConfig(ctx *cli.Context) error { + + config := defaultLedgerConfig + if ctx.Bool("mysql") { + config.DatabaseType = "mysql" + config.DatabaseLocation = "godbledger:password@tcp(127.0.0.1:3306)/ledger?charset=utf8" + } + + if len(ctx.Args().Get(0)) > 0 { + config.DatabaseLocation = ctx.Args().Get(0) + } + _, err := os.Stat(config.ConfigFile) + if os.IsNotExist(err) { + log.Infof("Config File doesn't exist creating at %s", config.ConfigFile) + os.MkdirAll(filepath.Dir(config.ConfigFile), os.ModePerm) + buf := new(bytes.Buffer) + if err := toml.NewEncoder(buf).Encode(config); err != nil { + return err + } + dump, err := os.OpenFile(config.ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer dump.Close() + dump.Write(buf.Bytes()) + } + + return nil +} diff --git a/godbledger/core/trialbalance.go b/godbledger/core/trialbalance.go index 80147d6..dbf2e15 100644 --- a/godbledger/core/trialbalance.go +++ b/godbledger/core/trialbalance.go @@ -2,19 +2,8 @@ package core import () -type Tag struct { - Name string `json:"Name"` - Total int `json:"Total"` - Accounts []PDFAccount `json:"Accounts"` -} - -type PDFAccount struct { - Account string `json:"Account"` - Amount int `json:"Amount"` -} - -var Reporteroutput struct { - Data []Tag `json:"Tags"` - Profit int `json:"Profit"` - NetAssets int `json:"NetAssets"` +type TBAccount struct { + Account string `json:"Account"` + Amount int `json:"Amount"` + Tags []string `json:"Tags"` } diff --git a/godbledger/db/database.go b/godbledger/db/database.go index 12754ac..95e10ee 100644 --- a/godbledger/db/database.go +++ b/godbledger/db/database.go @@ -27,6 +27,6 @@ type Database interface { FindUser(pubKey string) (*core.User, error) AddUser(usr *core.User) error SafeAddUser(usr *core.User) error - GetTB(date time.Time) error + GetTB(date time.Time) (*[]core.TBAccount, error) Query(query string, args ...interface{}) (*sql.Rows, error) } diff --git a/godbledger/db/mysql/mysqlfuncs.go b/godbledger/db/mysql/mysqlfuncs.go index 5de0cd9..ad266fb 100644 --- a/godbledger/db/mysql/mysqlfuncs.go +++ b/godbledger/db/mysql/mysqlfuncs.go @@ -427,63 +427,64 @@ func (db *Database) TestDB() error { return err } -func (db *Database) GetTB(date time.Time) error { +func (db *Database) GetTB(queryDate time.Time) (*[]core.TBAccount, error) { queryDB := ` - SELECT - tags.tag_name, - Table_Aggregate.account_id, - sums - FROM account_tag - join ((SELECT - split_accounts.account_id as account_id, - SUM(splits.amount) as sums - FROM splits - JOIN split_accounts - ON splits.split_id = split_accounts.split_id - GROUP BY split_accounts.account_id - - )) AS Table_Aggregate - on account_tag.account_id = Table_Aggregate.account_id - join tags - on tags.tag_id = account_tag.tag_id - order BY tags.tag_name + SELECT + split_accounts.account_id, + SUM(splits.amount) + FROM splits + JOIN split_accounts + ON splits.split_id = split_accounts.split_id + WHERE splits.split_date <= ? + GROUP BY split_accounts.account_id ;` - rows, err := db.DB.Query(queryDB) + log.Debug("Querying Database for Trial Balance") + + rows, err := db.DB.Query(queryDB, queryDate) if err != nil { - log.Debug(err) - return err + log.Fatal(err) } defer rows.Close() - accounts := make(map[string][]*core.PDFAccount) - totals := make(map[string]int) + accounts := []core.TBAccount{} for rows.Next() { - var t *core.PDFAccount - var name string - if err := rows.Scan(&name, &t.Account, &t.Amount); err != nil { + var t core.TBAccount + if err := rows.Scan(&t.Account, &t.Amount); err != nil { log.Fatal(err) } - log.Debugf("%v", t) - if val, ok := accounts[name]; ok { - accounts[name] = append(val, t) - totals[name] = totals[name] + t.Amount - } else { - accounts[name] = []*core.PDFAccount{t} - totals[name] = t.Amount - } + accounts = append(accounts, t) } if rows.Err() != nil { log.Fatal(err) } - //for k, v := range accounts { - //reporteroutput.Data = append(reporteroutput.Data, Tag{k, totals[k], v}) - //} + tagsQuery := ` + SELECT tag_name + FROM tags + JOIN account_tag + ON account_tag.tag_id = tags.tag_id + JOIN accounts + ON accounts.account_id = account_tag.account_id + WHERE accounts.NAME = ?; + ` + + for index, element := range accounts { + rows, err = db.DB.Query(tagsQuery, element.Account) + + for rows.Next() { + var tag string + if err := rows.Scan(&tag); err != nil { + log.Fatal(err) + } + accounts[index].Tags = append(accounts[index].Tags, tag) + } - return nil + } + + return &accounts, nil } diff --git a/godbledger/db/sqlite3/sqlite3funcs.go b/godbledger/db/sqlite3/sqlite3funcs.go index b895e52..036c4aa 100644 --- a/godbledger/db/sqlite3/sqlite3funcs.go +++ b/godbledger/db/sqlite3/sqlite3funcs.go @@ -427,66 +427,68 @@ func (db *Database) TestDB() error { return err } -func (db *Database) GetTB(date time.Time) error { +func (db *Database) GetTB(queryDate time.Time) (*[]core.TBAccount, error) { queryDB := ` - SELECT - tags.tag_name, - Table_Aggregate.account_id, - sums - FROM account_tag - join ((SELECT - split_accounts.account_id as account_id, - SUM(splits.amount) as sums - FROM splits - JOIN split_accounts - ON splits.split_id = split_accounts.split_id - GROUP BY split_accounts.account_id - - )) AS Table_Aggregate - on account_tag.account_id = Table_Aggregate.account_id - join tags - on tags.tag_id = account_tag.tag_id - order BY tags.tag_name + SELECT + split_accounts.account_id, + SUM(splits.amount) + FROM splits + JOIN split_accounts + ON splits.split_id = split_accounts.split_id + WHERE splits.split_date <= ? + GROUP BY split_accounts.account_id ;` - rows, err := db.DB.Query(queryDB) + log.Debug("Querying Database for Trial Balance") + + rows, err := db.DB.Query(queryDB, queryDate) if err != nil { - log.Debug(err) - return err + log.Fatal(err) } defer rows.Close() - accounts := make(map[string][]*core.PDFAccount) - totals := make(map[string]int) + accounts := []core.TBAccount{} for rows.Next() { - var t *core.PDFAccount - var name string - if err := rows.Scan(&name, &t.Account, &t.Amount); err != nil { + var t core.TBAccount + if err := rows.Scan(&t.Account, &t.Amount); err != nil { log.Fatal(err) } - log.Debugf("%v", t) - if val, ok := accounts[name]; ok { - accounts[name] = append(val, t) - totals[name] = totals[name] + t.Amount - } else { - accounts[name] = []*core.PDFAccount{t} - totals[name] = t.Amount - } + accounts = append(accounts, t) } if rows.Err() != nil { log.Fatal(err) } - //for k, v := range accounts { - ////reporteroutput.Data = append(reporteroutput.Data, Tag{k, totals[k], v}) - //} + tagsQuery := ` + SELECT tag_name + FROM tags + JOIN account_tag + ON account_tag.tag_id = tags.tag_id + JOIN accounts + ON accounts.account_id = account_tag.account_id + WHERE accounts.NAME = ?; + ` + + for index, element := range accounts { + rows, err = db.DB.Query(tagsQuery, element.Account) + + for rows.Next() { + var tag string + if err := rows.Scan(&tag); err != nil { + log.Fatal(err) + } + accounts[index].Tags = append(accounts[index].Tags, tag) + } + + } + + return &accounts, nil - return nil } func (db *Database) Query(query string, args ...interface{}) (*sql.Rows, error) { - return db.Query(query, args...) + return db.DB.Query(query, args...) } diff --git a/godbledger/ledger/ledger.go b/godbledger/ledger/ledger.go index 40d1a07..449694a 100644 --- a/godbledger/ledger/ledger.go +++ b/godbledger/ledger/ledger.go @@ -147,10 +147,8 @@ func (l *Ledger) GetAccounts(txn *core.Transaction) ([]*core.Account, error) { return accounts, nil } -func (l *Ledger) GetTB(date time.Time) (int, error) { - //accounts := []*core.Account{} - - return 1, nil +func (l *Ledger) GetTB(date time.Time) (*[]core.TBAccount, error) { + return l.LedgerDb.GetTB(date) } func (l *Ledger) Start() { diff --git a/godbledger/main.go b/godbledger/main.go index 580a204..35ece01 100644 --- a/godbledger/main.go +++ b/godbledger/main.go @@ -51,6 +51,7 @@ func main() { app.Commands = []*cli.Command{ // See config.go cmd.DumpConfigCommand, + cmd.InitConfigCommand, } app.Flags = []cli.Flag{ diff --git a/godbledger/rpc/ledger_server.go b/godbledger/rpc/ledger_server.go index 78e5bb3..cf49469 100644 --- a/godbledger/rpc/ledger_server.go +++ b/godbledger/rpc/ledger_server.go @@ -95,7 +95,20 @@ func (s *LedgerServer) DeleteTag(ctx context.Context, in *pb.DeleteTagRequest) ( func (s *LedgerServer) GetTB(ctx context.Context, in *pb.TBRequest) (*pb.TBResponse, error) { log.Info("Received New TB Request") - s.ld.GetTB(time.Now()) + accounts, err := s.ld.GetTB(time.Now()) - return &pb.TBResponse{}, nil + //log.Debug(accounts) + + response := pb.TBResponse{} + + for _, account := range *accounts { + response.Lines = append(response.Lines, + &pb.TBLine{ + Accountname: account.Account, + Amount: int64(account.Amount), + Tags: account.Tags, + }) + } + + return &response, err } diff --git a/godbledger/version/version.go b/godbledger/version/version.go index e516af3..ec8dbab 100644 --- a/godbledger/version/version.go +++ b/godbledger/version/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 0 // Major version component of the current release - VersionMinor = 1 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 0 // Major version component of the current release + VersionMinor = 2 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release + VersionMeta = "alpha" // Version metadata to append to the version string ) // Version holds the textual version string. diff --git a/ledger_cli/file.go b/ledger_cli/file.go index 78babf7..dc58fa7 100644 --- a/ledger_cli/file.go +++ b/ledger_cli/file.go @@ -1,16 +1,16 @@ -Copyright (c) 2013 Chris Howey +//Copyright (c) 2013 Chris Howey -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. +//Permission to use, copy, modify, and distribute this software for any +//purpose with or without fee is hereby granted, provided that the above +//copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +//THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +//WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +//MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +//ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +//WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +//ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +//OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. package main @@ -45,7 +45,9 @@ Loads a file in the ledger cli format columnWidth := 80 ledgerFileName = "test/transaction-codes-2.test" - //ledgerFileName = c.Args().Get(0) + if len(ctx.Args().Get(0)) > 0 { + ledgerFileName = ctx.Args().Get(0) + } ledgerFileReader, err := NewLedgerReader(ledgerFileName) if err != nil { diff --git a/ledger_cli/ledgerReader.go b/ledger_cli/ledgerReader.go index da04131..6c9e271 100644 --- a/ledger_cli/ledgerReader.go +++ b/ledger_cli/ledgerReader.go @@ -1,16 +1,16 @@ -Copyright (c) 2013 Chris Howey - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +//Copyright (c) 2013 Chris Howey + +//Permission to use, copy, modify, and distribute this software for any +//purpose with or without fee is hereby granted, provided that the above +//copyright notice and this permission notice appear in all copies. + +//THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +//WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +//MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +//ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +//WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +//ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +//OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. package main import ( diff --git a/ledger_cli/parse.go b/ledger_cli/parse.go index 9717eac..0e63f52 100644 --- a/ledger_cli/parse.go +++ b/ledger_cli/parse.go @@ -1,16 +1,16 @@ -Copyright (c) 2013 Chris Howey - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +//Copyright (c) 2013 Chris Howey + +//Permission to use, copy, modify, and distribute this software for any +//purpose with or without fee is hereby granted, provided that the above +//copyright notice and this permission notice appear in all copies. + +//THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +//WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +//MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +//ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +//WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +//ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +//OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. package main diff --git a/ledger_cli/types.go b/ledger_cli/types.go index df372c9..8936689 100644 --- a/ledger_cli/types.go +++ b/ledger_cli/types.go @@ -1,16 +1,16 @@ -Copyright (c) 2013 Chris Howey - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +//Copyright (c) 2013 Chris Howey + +//Permission to use, copy, modify, and distribute this software for any +//purpose with or without fee is hereby granted, provided that the above +//copyright notice and this permission notice appear in all copies. + +//THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +//WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +//MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +//ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +//WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +//ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +//OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. package main diff --git a/reporter/trialbalance.go b/reporter/trialbalance.go index 33a3a88..8a97c6d 100644 --- a/reporter/trialbalance.go +++ b/reporter/trialbalance.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "time" //"database/sql" "encoding/csv" @@ -56,8 +57,10 @@ If you want to see all the transactions in the database, or export to CSV //if err != nil { //log.Fatal(err) //} + queryDate := time.Now() + table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Account", "Balance"}) + table.SetHeader([]string{"Account", fmt.Sprintf("Balance at %s", queryDate.Format("02 February 2006"))}) table.SetBorder(false) queryDB := ` @@ -67,11 +70,12 @@ If you want to see all the transactions in the database, or export to CSV FROM splits JOIN split_accounts ON splits.split_id = split_accounts.split_id + WHERE splits.split_date <= ? GROUP BY split_accounts.account_id ;` log.Debug("Querying Database") - rows, err := ledger.LedgerDb.Query(queryDB) + rows, err := ledger.LedgerDb.Query(queryDB, queryDate) if err != nil { log.Fatal(err) }