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 +}