package server import ( "context" "fmt" "net/http" "time" "git.javil.eu/jacob1123/budgeteer/postgres" "git.javil.eu/jacob1123/budgeteer/postgres/numeric" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type NewTransactionPayload struct { Date JSONDate `json:"date"` Payee struct { ID uuid.NullUUID Name string IsAccount bool } `json:"payee"` CategoryID uuid.NullUUID `json:"categoryId"` Memo string `json:"memo"` Amount string `json:"amount"` BudgetID uuid.UUID `json:"budgetId"` AccountID uuid.UUID `json:"accountId"` State string `json:"state"` } func (h *Handler) newTransaction(c *gin.Context) { var payload NewTransactionPayload err := c.BindJSON(&payload) if err != nil { c.AbortWithError(http.StatusBadRequest, err) return } amount, err := numeric.Parse(payload.Amount) if err != nil { c.AbortWithError(http.StatusBadRequest, fmt.Errorf("amount: %w", err)) return } transactionID := c.Param("transactionid") if transactionID != "" { h.UpdateTransaction(payload, amount, transactionID, c) return } newTransaction := postgres.CreateTransactionParams{ Memo: payload.Memo, Date: time.Time(payload.Date), Amount: amount, Status: postgres.TransactionStatus(payload.State), CategoryID: payload.CategoryID, AccountID: payload.AccountID, } if payload.Payee.IsAccount { err := h.CreateTransferForOtherAccount(newTransaction, amount, payload, c) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) return } } else { payeeID, err := GetPayeeID(c.Request.Context(), payload, h) if err != nil { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("create payee: %w", err)) } newTransaction.PayeeID = payeeID } transaction, err := h.Service.CreateTransaction(c.Request.Context(), newTransaction) if err != nil { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("create transaction: %w", err)) return } c.JSON(http.StatusOK, transaction) } func (h *Handler) UpdateTransaction(payload NewTransactionPayload, amount numeric.Numeric, transactionID string, c *gin.Context) { editTransaction := postgres.UpdateTransactionParams{ Memo: payload.Memo, Date: time.Time(payload.Date), Amount: amount, PayeeID: payload.Payee.ID, CategoryID: payload.CategoryID, ID: uuid.MustParse(transactionID), } err := h.Service.UpdateTransaction(c.Request.Context(), editTransaction) if err != nil { c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("edit transaction: %w", err)) } } func (h *Handler) CreateTransferForOtherAccount(newTransaction postgres.CreateTransactionParams, amount numeric.Numeric, payload NewTransactionPayload, c *gin.Context) error { newTransaction.GroupID = uuid.NullUUID{UUID: uuid.New(), Valid: true} newTransaction.Amount = amount.Neg() newTransaction.AccountID = payload.Payee.ID.UUID // transfer does not need category. Either it's account is off-budget or no category was supplied. newTransaction.CategoryID = uuid.NullUUID{} _, err := h.Service.CreateTransaction(c.Request.Context(), newTransaction) return fmt.Errorf("create transfer transaction: %w", err) } 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 }