From 5ccec6146545d2b2d67309a3284dc513e5065c42 Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Wed, 23 Feb 2022 22:53:04 +0000 Subject: [PATCH 1/5] Implement transfer creation --- postgres/accounts.sql.go | 16 +++++--- postgres/numeric/numeric.go | 4 ++ postgres/queries/accounts.sql | 2 +- server/transaction.go | 73 +++++++++++++++++++++++------------ 4 files changed, 65 insertions(+), 30 deletions(-) diff --git a/postgres/accounts.sql.go b/postgres/accounts.sql.go index 4d15658..20d30df 100644 --- a/postgres/accounts.sql.go +++ b/postgres/accounts.sql.go @@ -130,7 +130,7 @@ func (q *Queries) GetAccountsWithBalance(ctx context.Context, budgetID uuid.UUID } const searchAccounts = `-- name: SearchAccounts :many -SELECT accounts.id, accounts.budget_id, accounts.name FROM accounts +SELECT accounts.id, accounts.budget_id, accounts.name, true as is_account FROM accounts WHERE accounts.budget_id = $1 AND accounts.name LIKE $2 ORDER BY accounts.name @@ -142,9 +142,10 @@ type SearchAccountsParams struct { } type SearchAccountsRow struct { - ID uuid.UUID - BudgetID uuid.UUID - Name string + ID uuid.UUID + BudgetID uuid.UUID + Name string + IsAccount bool } func (q *Queries) SearchAccounts(ctx context.Context, arg SearchAccountsParams) ([]SearchAccountsRow, error) { @@ -156,7 +157,12 @@ func (q *Queries) SearchAccounts(ctx context.Context, arg SearchAccountsParams) var items []SearchAccountsRow for rows.Next() { var i SearchAccountsRow - if err := rows.Scan(&i.ID, &i.BudgetID, &i.Name); err != nil { + if err := rows.Scan( + &i.ID, + &i.BudgetID, + &i.Name, + &i.IsAccount, + ); err != nil { return nil, err } items = append(items, i) diff --git a/postgres/numeric/numeric.go b/postgres/numeric/numeric.go index cf1ff73..753feff 100644 --- a/postgres/numeric/numeric.go +++ b/postgres/numeric/numeric.go @@ -83,6 +83,10 @@ func (n Numeric) Sub(other Numeric) Numeric { panic("Cannot subtract with different exponents") } +func (n Numeric) Neg() Numeric { + return Numeric{pgtype.Numeric{Exp: n.Exp, Int: big.NewInt(-1 * n.Int.Int64()), Status: n.Status}} +} + func (n Numeric) Add(other Numeric) Numeric { left := n right := other diff --git a/postgres/queries/accounts.sql b/postgres/queries/accounts.sql index a7b969e..62173d9 100644 --- a/postgres/queries/accounts.sql +++ b/postgres/queries/accounts.sql @@ -22,7 +22,7 @@ GROUP BY accounts.id, accounts.name ORDER BY accounts.name; -- name: SearchAccounts :many -SELECT accounts.id, accounts.budget_id, accounts.name FROM accounts +SELECT accounts.id, accounts.budget_id, accounts.name, true as is_account FROM accounts WHERE accounts.budget_id = @budget_id AND accounts.name LIKE @search ORDER BY accounts.name; \ No newline at end of file diff --git a/server/transaction.go b/server/transaction.go index d3cad1b..4f91c06 100644 --- a/server/transaction.go +++ b/server/transaction.go @@ -1,6 +1,7 @@ package server import ( + "context" "fmt" "net/http" "time" @@ -14,8 +15,9 @@ import ( type NewTransactionPayload struct { Date JSONDate `json:"date"` Payee struct { - ID uuid.NullUUID - Name string + ID uuid.NullUUID + Name string + IsAccount bool } `json:"payee"` Category struct { ID uuid.NullUUID @@ -36,39 +38,40 @@ func (h *Handler) newTransaction(c *gin.Context) { return } - amount := numeric.Numeric{} - err = amount.Set(payload.Amount) + amount, err := numeric.Parse(payload.Amount) if err != nil { c.AbortWithError(http.StatusBadRequest, fmt.Errorf("amount: %w", err)) return } - payeeID := payload.Payee.ID - if !payeeID.Valid && payload.Payee.Name != "" { - newPayee := postgres.CreatePayeeParams{ - Name: payload.Payee.Name, - BudgetID: payload.BudgetID, + newTransaction := postgres.CreateTransactionParams{ + Memo: payload.Memo, + Date: time.Time(payload.Date), + Amount: amount, + Status: postgres.TransactionStatus(payload.State), + } + + if payload.Payee.IsAccount { + newTransaction.GroupID = uuid.NullUUID{UUID: uuid.New(), Valid: true} + newTransaction.Amount = amount.Neg() + newTransaction.AccountID = payload.Payee.ID.UUID + newTransaction.CategoryID = uuid.NullUUID{} + + _, err = h.Service.CreateTransaction(c.Request.Context(), newTransaction) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("create transfer transaction: %w", err)) + return } - payee, err := h.Service.CreatePayee(c.Request.Context(), newPayee) + } else { + payeeID, err := GetPayeeID(c.Request.Context(), payload, h) if err != nil { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("create payee: %w", err)) } - - payeeID = uuid.NullUUID{ - UUID: payee.ID, - Valid: true, - } + newTransaction.PayeeID = payeeID } - newTransaction := postgres.CreateTransactionParams{ - Memo: payload.Memo, - Date: time.Time(payload.Date), - Amount: amount, - AccountID: payload.AccountID, - PayeeID: payeeID, - CategoryID: payload.Category.ID, - Status: postgres.TransactionStatus(payload.State), - } + newTransaction.CategoryID = payload.Category.ID + newTransaction.AccountID = payload.AccountID transaction, err := h.Service.CreateTransaction(c.Request.Context(), newTransaction) if err != nil { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("create transaction: %w", err)) @@ -77,3 +80,25 @@ func (h *Handler) newTransaction(c *gin.Context) { c.JSON(http.StatusOK, transaction) } + +func GetPayeeID(context context.Context, payload NewTransactionPayload, h *Handler) (uuid.NullUUID, error) { + payeeID := payload.Payee.ID + if payeeID.Valid { + return payeeID, nil + } + + if payload.Payee.Name == "" { + return uuid.NullUUID{}, nil + } + + newPayee := postgres.CreatePayeeParams{ + Name: payload.Payee.Name, + BudgetID: payload.BudgetID, + } + payee, err := h.Service.CreatePayee(context, newPayee) + if err != nil { + return uuid.NullUUID{}, fmt.Errorf("create payee: %w", err) + } + + return uuid.NullUUID{UUID: payee.ID, Valid: true}, nil +} -- 2.47.2 From bbbeff92e83f1844cec4c01d531c8a3f3217b8cc Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Wed, 23 Feb 2022 22:55:15 +0000 Subject: [PATCH 2/5] Reset amount to positive after saving transfer transaction --- server/transaction.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/transaction.go b/server/transaction.go index 4f91c06..979614b 100644 --- a/server/transaction.go +++ b/server/transaction.go @@ -62,6 +62,8 @@ func (h *Handler) newTransaction(c *gin.Context) { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("create transfer transaction: %w", err)) return } + + newTransaction.Amount = amount } else { payeeID, err := GetPayeeID(c.Request.Context(), payload, h) if err != nil { -- 2.47.2 From ddf51b5922404138b530ec8fe75de44b355ab16b Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Wed, 23 Feb 2022 23:03:18 +0000 Subject: [PATCH 3/5] Use store instead of props in BudgetSidebar --- web/src/pages/BudgetSidebar.vue | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/web/src/pages/BudgetSidebar.vue b/web/src/pages/BudgetSidebar.vue index 764ed67..9ae0fa7 100644 --- a/web/src/pages/BudgetSidebar.vue +++ b/web/src/pages/BudgetSidebar.vue @@ -5,11 +5,6 @@ import { useBudgetsStore } from "../stores/budget" import { useAccountStore } from "../stores/budget-account" import { useSettingsStore } from "../stores/settings" -const props = defineProps<{ - budgetid: string, - accountid: string, -}>(); - const ExpandMenu = computed(() => useSettingsStore().Menu.Expand); const budgetStore = useBudgetsStore(); @@ -30,7 +25,7 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa {{CurrentBudgetName}} - Budget
+ Budget
@@ -40,7 +35,7 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa
- {{account.Name}} + {{account.Name}}
@@ -50,7 +45,7 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa
- {{account.Name}} + {{account.Name}}
-- 2.47.2 From 635f4de402b488164888d52f5e92e42e62f80978 Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Wed, 23 Feb 2022 23:03:31 +0000 Subject: [PATCH 4/5] Fix initialize of Budgets after login --- web/src/stores/session.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/src/stores/session.ts b/web/src/stores/session.ts index 49a2807..cf61e2f 100644 --- a/web/src/stores/session.ts +++ b/web/src/stores/session.ts @@ -36,8 +36,10 @@ export const useSessionStore = defineStore('session', { this.Session = { User: x.User, Token: x.Token, - }, - this.Budgets = x.Budgets; + } + for (const budget of x.Budgets) { + this.Budgets.set(budget.ID, budget); + } }, async login(login: any) { const response = await POST("/user/login", JSON.stringify(login)); -- 2.47.2 From 966c0ce0ebb901e2c6670b77cec91e9676b804a4 Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Wed, 23 Feb 2022 23:12:39 +0000 Subject: [PATCH 5/5] Redesign Budget Settings and introduce Button component --- web/src/components/Button.vue | 8 ++++++ web/src/pages/Settings.vue | 51 +++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 web/src/components/Button.vue diff --git a/web/src/components/Button.vue b/web/src/components/Button.vue new file mode 100644 index 0000000..ff7554f --- /dev/null +++ b/web/src/components/Button.vue @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/web/src/pages/Settings.vue b/web/src/pages/Settings.vue index d8467a0..6550a11 100644 --- a/web/src/pages/Settings.vue +++ b/web/src/pages/Settings.vue @@ -5,6 +5,7 @@ import { DELETE, POST } from "../api"; import { useBudgetsStore } from "../stores/budget"; import { useSessionStore } from "../stores/session"; import Card from "../components/Card.vue"; +import Button from "../components/Button.vue"; const transactionsFile = ref(undefined); const assignmentsFile = ref(undefined); @@ -57,37 +58,41 @@ function ynabImport() {