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..979614b 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,42 @@ 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)
+
+ newTransaction.Amount = amount
+ } 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 +82,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
+}
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/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}}
-
+
@@ -40,7 +35,7 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa
This removes transactions and assignments to start from scratch. Accounts and categories are kept. Not undoable!
- +This deletes the whole bugdet including all transactions, assignments, accounts and categories. Not undoable!
- +This restores YNABs functionality, that would substract any overspent categories' balances from next months inflows.
- +