Add budgeting
This commit is contained in:
parent
8f374f1d62
commit
53c51ceb8d
70
http/budgeting.go
Normal file
70
http/budgeting.go
Normal file
@ -0,0 +1,70 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.javil.eu/jacob1123/budgeteer/postgres"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type BudgetingData struct {
|
||||
AlwaysNeededData
|
||||
Categories []postgres.GetCategoriesWithBalanceRow
|
||||
}
|
||||
|
||||
func (h *Handler) budgeting(c *gin.Context) {
|
||||
budgetID := c.Param("budgetid")
|
||||
budgetUUID, err := uuid.Parse(budgetID)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusTemporaryRedirect, "/login")
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var year, month int
|
||||
yearString := c.Param("year")
|
||||
monthString := c.Param("month")
|
||||
if yearString != "" && monthString != "" {
|
||||
year, err = strconv.Atoi(yearString)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusTemporaryRedirect, "/budget/"+budgetUUID.String())
|
||||
return
|
||||
}
|
||||
|
||||
month, err = strconv.Atoi(monthString)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusTemporaryRedirect, "/budget/"+budgetUUID.String())
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
var monthM time.Month
|
||||
year, monthM, _ = now.Date()
|
||||
month = int(monthM)
|
||||
}
|
||||
|
||||
firstOfMonth := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, now.Location())
|
||||
lastOfMonth := firstOfMonth.AddDate(0, 1, -1)
|
||||
|
||||
params := postgres.GetCategoriesWithBalanceParams{
|
||||
BudgetID: budgetUUID,
|
||||
FromDate: firstOfMonth,
|
||||
ToDate: lastOfMonth,
|
||||
}
|
||||
categories, err := h.Service.DB.GetCategoriesWithBalance(context.Background(), params)
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
d := BudgetingData{
|
||||
c.MustGet("data").(AlwaysNeededData),
|
||||
categories,
|
||||
}
|
||||
|
||||
c.HTML(http.StatusOK, "budgeting.html", d)
|
||||
}
|
@ -57,6 +57,7 @@ func (h *Handler) Serve() {
|
||||
withBudget.Use(h.verifyLoginWithRedirect)
|
||||
withBudget.Use(h.getImportantData)
|
||||
withBudget.GET("/budget/:budgetid", h.budgeting)
|
||||
withBudget.GET("/budget/:budgetid/:year/:month", h.budgeting)
|
||||
withBudget.GET("/budget/:budgetid/all-accounts", h.budget)
|
||||
withBudget.GET("/budget/:budgetid/accounts", h.accounts)
|
||||
withBudget.GET("/budget/:budgetid/account/:accountid", h.account)
|
||||
|
@ -90,11 +90,25 @@ func (q *Queries) GetCategories(ctx context.Context, budgetID uuid.UUID) ([]GetC
|
||||
}
|
||||
|
||||
const getCategoriesWithBalance = `-- name: GetCategoriesWithBalance :many
|
||||
SELECT categories.id, categories.name, category_groups.name as group, SUM(t_hist.amount)::decimal(12,2) as balance, SUM(t_this.amount)::decimal(12,2) as activity
|
||||
SELECT categories.id, categories.name, category_groups.name as group,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT SUM(t_hist.amount)
|
||||
FROM transactions t_hist
|
||||
WHERE categories.id = t_hist.category_id
|
||||
AND t_hist.date < $1
|
||||
)
|
||||
, 0)::decimal(12,2) as balance,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT SUM(t_this.amount)
|
||||
FROM transactions t_this
|
||||
WHERE categories.id = t_this.category_id
|
||||
AND t_this.date BETWEEN $1 AND $2
|
||||
)
|
||||
, 0)::decimal(12,2) as activity
|
||||
FROM categories
|
||||
INNER JOIN category_groups ON categories.category_group_id = category_groups.id
|
||||
INNER JOIN transactions t_hist ON categories.id = t_hist.category_id AND t_hist.date < $1
|
||||
INNER JOIN transactions t_this ON categories.id = t_this.category_id AND t_this.date >= $1 AND t_this.date < $2
|
||||
WHERE category_groups.budget_id = $3
|
||||
GROUP BY categories.id, categories.name, category_groups.name
|
||||
`
|
||||
|
@ -20,10 +20,24 @@ INNER JOIN category_groups ON categories.category_group_id = category_groups.id
|
||||
WHERE category_groups.budget_id = $1;
|
||||
|
||||
-- name: GetCategoriesWithBalance :many
|
||||
SELECT categories.id, categories.name, category_groups.name as group, SUM(t_hist.amount)::decimal(12,2) as balance, SUM(t_this.amount)::decimal(12,2) as activity
|
||||
SELECT categories.id, categories.name, category_groups.name as group,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT SUM(t_hist.amount)
|
||||
FROM transactions t_hist
|
||||
WHERE categories.id = t_hist.category_id
|
||||
AND t_hist.date < @from_date
|
||||
)
|
||||
, 0)::decimal(12,2) as balance,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT SUM(t_this.amount)
|
||||
FROM transactions t_this
|
||||
WHERE categories.id = t_this.category_id
|
||||
AND t_this.date BETWEEN @from_date AND @to_date
|
||||
)
|
||||
, 0)::decimal(12,2) as activity
|
||||
FROM categories
|
||||
INNER JOIN category_groups ON categories.category_group_id = category_groups.id
|
||||
INNER JOIN transactions t_hist ON categories.id = t_hist.category_id AND t_hist.date < @from_date
|
||||
INNER JOIN transactions t_this ON categories.id = t_this.category_id AND t_this.date >= @from_date AND t_this.date < @to_date
|
||||
WHERE category_groups.budget_id = @budget_id
|
||||
GROUP BY categories.id, categories.name, category_groups.name;
|
37
web/budgeting.html
Normal file
37
web/budgeting.html
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "title"}}Budget{{end}}
|
||||
|
||||
{{define "new"}}
|
||||
{{template "transaction-new"}}
|
||||
{{end}}
|
||||
|
||||
{{define "main"}}
|
||||
<div class="budget-item">
|
||||
<a href="#newtransactionmodal" data-toggle="modal" data-target="#newtransactionmodal">New Transaction</a>
|
||||
<span class="time"></span>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/budget/{{.Budget.ID}}/{{.Date.Year}}/{{.Date.Month}}">Next Month</a>
|
||||
<a href="/budget/{{.Budget.ID}}/{{.Date.Year}}/{{.Date.Month}}">Previous Month</a>
|
||||
</div>
|
||||
<table class="container col-lg-12" id="content">
|
||||
{{range .Categories}}
|
||||
<tr>
|
||||
<td>{{.Group}}</td>
|
||||
<td>{{.Name}}</td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
<td style="text-align: right;{{if .Balance.GetPositive}}{{else}}color: red;{{end}}">
|
||||
{{printf "%.2f" .Balance.GetFloat64}}
|
||||
</td>
|
||||
<td style="text-align: right;{{if .Activity.GetPositive}}{{else}}color: red;{{end}}">
|
||||
{{printf "%.2f" .Activity.GetFloat64}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
{{end}}
|
Loading…
x
Reference in New Issue
Block a user