feat: add finance module (categories, transactions, summary, analytics)
All checks were successful
CI / ci (push) Successful in 12s
All checks were successful
CI / ci (push) Successful in 12s
- model/finance.go: FinanceCategory, FinanceTransaction, Summary, Analytics - repository/finance.go: CRUD + summary/analytics queries - service/finance.go: business logic with auto-seed default categories - handler/finance.go: REST endpoints with owner-only check (user_id=1) - db.go: finance_categories + finance_transactions migrations - main.go: register /finance/* routes Endpoints: GET/POST/PUT/DELETE /finance/categories, /finance/transactions GET /finance/summary, /finance/analytics
This commit is contained in:
114
internal/model/finance.go
Normal file
114
internal/model/finance.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FinanceCategory struct {
|
||||
ID int64 `db:"id" json:"id"`
|
||||
UserID int64 `db:"user_id" json:"user_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Emoji string `db:"emoji" json:"emoji"`
|
||||
Type string `db:"type" json:"type"`
|
||||
Budget sql.NullFloat64 `db:"budget" json:"-"`
|
||||
BudgetVal *float64 `db:"-" json:"budget"`
|
||||
Color string `db:"color" json:"color"`
|
||||
SortOrder int `db:"sort_order" json:"sort_order"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
func (c *FinanceCategory) ProcessForJSON() {
|
||||
if c.Budget.Valid {
|
||||
c.BudgetVal = &c.Budget.Float64
|
||||
}
|
||||
}
|
||||
|
||||
type FinanceTransaction struct {
|
||||
ID int64 `db:"id" json:"id"`
|
||||
UserID int64 `db:"user_id" json:"user_id"`
|
||||
CategoryID int64 `db:"category_id" json:"category_id"`
|
||||
Type string `db:"type" json:"type"`
|
||||
Amount float64 `db:"amount" json:"amount"`
|
||||
Description string `db:"description" json:"description"`
|
||||
Date time.Time `db:"date" json:"date"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
// Joined fields
|
||||
CategoryName string `db:"category_name" json:"category_name,omitempty"`
|
||||
CategoryEmoji string `db:"category_emoji" json:"category_emoji,omitempty"`
|
||||
}
|
||||
|
||||
type CreateFinanceCategoryRequest struct {
|
||||
Name string `json:"name"`
|
||||
Emoji string `json:"emoji,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Budget *float64 `json:"budget,omitempty"`
|
||||
Color string `json:"color,omitempty"`
|
||||
SortOrder int `json:"sort_order,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateFinanceCategoryRequest struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Emoji *string `json:"emoji,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Budget *float64 `json:"budget,omitempty"`
|
||||
Color *string `json:"color,omitempty"`
|
||||
SortOrder *int `json:"sort_order,omitempty"`
|
||||
}
|
||||
|
||||
type CreateFinanceTransactionRequest struct {
|
||||
CategoryID int64 `json:"category_id"`
|
||||
Type string `json:"type"`
|
||||
Amount float64 `json:"amount"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Date string `json:"date"`
|
||||
}
|
||||
|
||||
type UpdateFinanceTransactionRequest struct {
|
||||
CategoryID *int64 `json:"category_id,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Amount *float64 `json:"amount,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Date *string `json:"date,omitempty"`
|
||||
}
|
||||
|
||||
type FinanceSummary struct {
|
||||
Balance float64 `json:"balance"`
|
||||
TotalIncome float64 `json:"total_income"`
|
||||
TotalExpense float64 `json:"total_expense"`
|
||||
ByCategory []CategorySummary `json:"by_category"`
|
||||
Daily []DailySummary `json:"daily"`
|
||||
}
|
||||
|
||||
type CategorySummary struct {
|
||||
CategoryID int64 `json:"category_id" db:"category_id"`
|
||||
CategoryName string `json:"category_name" db:"category_name"`
|
||||
CategoryEmoji string `json:"category_emoji" db:"category_emoji"`
|
||||
Type string `json:"type" db:"type"`
|
||||
Amount float64 `json:"amount" db:"amount"`
|
||||
Percentage float64 `json:"percentage"`
|
||||
Budget *float64 `json:"budget,omitempty"`
|
||||
}
|
||||
|
||||
type DailySummary struct {
|
||||
Date string `json:"date" db:"date"`
|
||||
Amount float64 `json:"amount" db:"amount"`
|
||||
}
|
||||
|
||||
type FinanceAnalytics struct {
|
||||
MonthlyTrend []MonthlyTrend `json:"monthly_trend"`
|
||||
AvgDailyExpense float64 `json:"avg_daily_expense"`
|
||||
ComparisonPrevMonth Comparison `json:"comparison_prev_month"`
|
||||
}
|
||||
|
||||
type MonthlyTrend struct {
|
||||
Month string `json:"month" db:"month"`
|
||||
Income float64 `json:"income" db:"income"`
|
||||
Expense float64 `json:"expense" db:"expense"`
|
||||
}
|
||||
|
||||
type Comparison struct {
|
||||
Current float64 `json:"current"`
|
||||
Previous float64 `json:"previous"`
|
||||
DiffPercent float64 `json:"diff_percent"`
|
||||
}
|
||||
Reference in New Issue
Block a user