diff --git a/postgres/models.go b/postgres/models.go index 1e45f17..81ba49b 100644 --- a/postgres/models.go +++ b/postgres/models.go @@ -4,11 +4,32 @@ package postgres import ( "database/sql" + "fmt" "time" "github.com/google/uuid" ) +type TransactionStatus string + +const ( + TransactionStatusReconciled TransactionStatus = "Reconciled" + TransactionStatusCleared TransactionStatus = "Cleared" + TransactionStatusUncleared TransactionStatus = "Uncleared" +) + +func (e *TransactionStatus) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = TransactionStatus(s) + case string: + *e = TransactionStatus(s) + default: + return fmt.Errorf("unsupported scan type for TransactionStatus: %T", src) + } + return nil +} + type Account struct { ID uuid.UUID BudgetID uuid.UUID @@ -65,6 +86,7 @@ type Transaction struct { CategoryID uuid.NullUUID PayeeID uuid.NullUUID GroupID uuid.NullUUID + Status TransactionStatus } type TransactionsByMonth struct { diff --git a/postgres/queries/transactions.sql b/postgres/queries/transactions.sql index 3c4aa3f..2bfbf15 100644 --- a/postgres/queries/transactions.sql +++ b/postgres/queries/transactions.sql @@ -4,8 +4,8 @@ WHERE id = $1; -- name: CreateTransaction :one INSERT INTO transactions -(date, memo, amount, account_id, payee_id, category_id, group_id) -VALUES ($1, $2, $3, $4, $5, $6, $7) +(date, memo, amount, account_id, payee_id, category_id, group_id, status) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *; -- name: UpdateTransaction :exec @@ -23,7 +23,7 @@ DELETE FROM transactions WHERE id = $1; -- name: GetTransactionsForBudget :many -SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, +SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, transactions.status, accounts.name as account, COALESCE(payees.name, '') as payee, COALESCE(category_groups.name, '') as category_group, COALESCE(categories.name, '') as category FROM transactions INNER JOIN accounts ON accounts.id = transactions.account_id @@ -35,7 +35,7 @@ ORDER BY transactions.date DESC LIMIT 200; -- name: GetTransactionsForAccount :many -SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, +SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, transactions.status, accounts.name as account, COALESCE(payees.name, '') as payee, COALESCE(category_groups.name, '') as category_group, COALESCE(categories.name, '') as category FROM transactions INNER JOIN accounts ON accounts.id = transactions.account_id diff --git a/postgres/schema/0013_add-transaction-status.sql b/postgres/schema/0013_add-transaction-status.sql new file mode 100644 index 0000000..718b022 --- /dev/null +++ b/postgres/schema/0013_add-transaction-status.sql @@ -0,0 +1,12 @@ +-- +goose Up +CREATE TYPE transaction_status AS ENUM ( + 'Reconciled', + 'Cleared', + 'Uncleared' +); + +ALTER TABLE transactions ADD COLUMN status transaction_status NOT NULL DEFAULT 'Uncleared'; + +-- +goose Down +ALTER TABLE transactions DROP COLUMN status; +DROP TYPE transaction_status; diff --git a/postgres/transactions.sql.go b/postgres/transactions.sql.go index e3fc971..b1798ed 100644 --- a/postgres/transactions.sql.go +++ b/postgres/transactions.sql.go @@ -12,9 +12,9 @@ import ( const createTransaction = `-- name: CreateTransaction :one INSERT INTO transactions -(date, memo, amount, account_id, payee_id, category_id, group_id) -VALUES ($1, $2, $3, $4, $5, $6, $7) -RETURNING id, date, memo, amount, account_id, category_id, payee_id, group_id +(date, memo, amount, account_id, payee_id, category_id, group_id, status) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8) +RETURNING id, date, memo, amount, account_id, category_id, payee_id, group_id, status ` type CreateTransactionParams struct { @@ -25,6 +25,7 @@ type CreateTransactionParams struct { PayeeID uuid.NullUUID CategoryID uuid.NullUUID GroupID uuid.NullUUID + Status TransactionStatus } func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionParams) (Transaction, error) { @@ -36,6 +37,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa arg.PayeeID, arg.CategoryID, arg.GroupID, + arg.Status, ) var i Transaction err := row.Scan( @@ -47,6 +49,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa &i.CategoryID, &i.PayeeID, &i.GroupID, + &i.Status, ) return i, err } @@ -77,7 +80,7 @@ func (q *Queries) DeleteTransaction(ctx context.Context, id uuid.UUID) error { } const getTransaction = `-- name: GetTransaction :one -SELECT id, date, memo, amount, account_id, category_id, payee_id, group_id FROM transactions +SELECT id, date, memo, amount, account_id, category_id, payee_id, group_id, status FROM transactions WHERE id = $1 ` @@ -93,6 +96,7 @@ func (q *Queries) GetTransaction(ctx context.Context, id uuid.UUID) (Transaction &i.CategoryID, &i.PayeeID, &i.GroupID, + &i.Status, ) return i, err } @@ -132,7 +136,7 @@ func (q *Queries) GetTransactionsByMonthAndCategory(ctx context.Context, budgetI } const getTransactionsForAccount = `-- name: GetTransactionsForAccount :many -SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, +SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, transactions.status, accounts.name as account, COALESCE(payees.name, '') as payee, COALESCE(category_groups.name, '') as category_group, COALESCE(categories.name, '') as category FROM transactions INNER JOIN accounts ON accounts.id = transactions.account_id @@ -150,6 +154,7 @@ type GetTransactionsForAccountRow struct { Memo string Amount Numeric GroupID uuid.NullUUID + Status TransactionStatus Account string Payee string CategoryGroup string @@ -171,6 +176,7 @@ func (q *Queries) GetTransactionsForAccount(ctx context.Context, accountID uuid. &i.Memo, &i.Amount, &i.GroupID, + &i.Status, &i.Account, &i.Payee, &i.CategoryGroup, @@ -190,7 +196,7 @@ func (q *Queries) GetTransactionsForAccount(ctx context.Context, accountID uuid. } const getTransactionsForBudget = `-- name: GetTransactionsForBudget :many -SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, +SELECT transactions.id, transactions.date, transactions.memo, transactions.amount, transactions.group_id, transactions.status, accounts.name as account, COALESCE(payees.name, '') as payee, COALESCE(category_groups.name, '') as category_group, COALESCE(categories.name, '') as category FROM transactions INNER JOIN accounts ON accounts.id = transactions.account_id @@ -208,6 +214,7 @@ type GetTransactionsForBudgetRow struct { Memo string Amount Numeric GroupID uuid.NullUUID + Status TransactionStatus Account string Payee string CategoryGroup string @@ -229,6 +236,7 @@ func (q *Queries) GetTransactionsForBudget(ctx context.Context, budgetID uuid.UU &i.Memo, &i.Amount, &i.GroupID, + &i.Status, &i.Account, &i.Payee, &i.CategoryGroup, diff --git a/postgres/ynab-import.go b/postgres/ynab-import.go index a0b6481..a9b8891 100644 --- a/postgres/ynab-import.go +++ b/postgres/ynab-import.go @@ -165,12 +165,23 @@ func (ynab *YNABImport) ImportTransactions(r io.Reader) error { return fmt.Errorf("could not parse amount from (%s/%s): %w", inflow, outflow, err) } + statusEnum := TransactionStatusUncleared + status := record[10] + switch status { + case "Cleared": + statusEnum = TransactionStatusCleared + case "Reconciled": + statusEnum = TransactionStatusReconciled + case "Uncleared": + } + transaction := CreateTransactionParams{ Date: date, Memo: memo, AccountID: account.ID, CategoryID: category, Amount: amount, + Status: statusEnum, } payeeName := record[3] @@ -237,8 +248,6 @@ func (ynab *YNABImport) ImportTransactions(r io.Reader) error { } } - //status := record[10] - count++ } diff --git a/web/account.html b/web/account.html index b3af46f..ee6933e 100644 --- a/web/account.html +++ b/web/account.html @@ -33,6 +33,9 @@ {{.Memo}} {{template "amount-cell" .Amount}} + + {{.Status}} + {{end}}