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.verifyLoginWithRedirect)
|
||||||
withBudget.Use(h.getImportantData)
|
withBudget.Use(h.getImportantData)
|
||||||
withBudget.GET("/budget/:budgetid", h.budgeting)
|
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/all-accounts", h.budget)
|
||||||
withBudget.GET("/budget/:budgetid/accounts", h.accounts)
|
withBudget.GET("/budget/:budgetid/accounts", h.accounts)
|
||||||
withBudget.GET("/budget/:budgetid/account/:accountid", h.account)
|
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
|
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
|
FROM categories
|
||||||
INNER JOIN category_groups ON categories.category_group_id = category_groups.id
|
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
|
WHERE category_groups.budget_id = $3
|
||||||
GROUP BY categories.id, categories.name, category_groups.name
|
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;
|
WHERE category_groups.budget_id = $1;
|
||||||
|
|
||||||
-- name: GetCategoriesWithBalance :many
|
-- 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
|
FROM categories
|
||||||
INNER JOIN category_groups ON categories.category_group_id = category_groups.id
|
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
|
WHERE category_groups.budget_id = @budget_id
|
||||||
GROUP BY categories.id, categories.name, category_groups.name;
|
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