chore: replace int amount_cents for string storage and decimal pkg

This commit is contained in:
juancwu 2026-03-14 14:43:39 -04:00
commit c8a1eb5b7a
No known key found for this signature in database
45 changed files with 706 additions and 587 deletions

View file

@ -3,6 +3,8 @@ package model
import (
"strings"
"time"
"github.com/shopspring/decimal"
)
type BudgetPeriod string
@ -22,22 +24,23 @@ const (
)
type Budget struct {
ID string `db:"id"`
SpaceID string `db:"space_id"`
AmountCents int `db:"amount_cents"`
Period BudgetPeriod `db:"period"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
IsActive bool `db:"is_active"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
SpaceID string `db:"space_id"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
Period BudgetPeriod `db:"period"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
IsActive bool `db:"is_active"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type BudgetWithSpent struct {
Budget
Tags []*Tag
SpentCents int
Spent decimal.Decimal
Percentage float64
Status BudgetStatus
}

View file

@ -1,6 +1,10 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type ExpenseType string
@ -10,17 +14,18 @@ const (
)
type Expense struct {
ID string `db:"id"`
SpaceID string `db:"space_id"`
CreatedBy string `db:"created_by"`
Description string `db:"description"`
AmountCents int `db:"amount_cents"`
Type ExpenseType `db:"type"`
Date time.Time `db:"date"`
PaymentMethodID *string `db:"payment_method_id"`
RecurringExpenseID *string `db:"recurring_expense_id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
SpaceID string `db:"space_id"`
CreatedBy string `db:"created_by"`
Description string `db:"description"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
Type ExpenseType `db:"type"`
Date time.Time `db:"date"`
PaymentMethodID *string `db:"payment_method_id"`
RecurringExpenseID *string `db:"recurring_expense_id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type ExpenseWithTags struct {
@ -45,8 +50,8 @@ type ExpenseItem struct {
}
type TagExpenseSummary struct {
TagID string `db:"tag_id"`
TagName string `db:"tag_name"`
TagColor *string `db:"tag_color"`
TotalAmount int `db:"total_amount"`
TagID string `db:"tag_id"`
TagName string `db:"tag_name"`
TagColor *string `db:"tag_color"`
TotalAmount decimal.Decimal `db:"total_amount"`
}

View file

@ -1,25 +1,30 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type Loan struct {
ID string `db:"id"`
SpaceID string `db:"space_id"`
Name string `db:"name"`
Description string `db:"description"`
OriginalAmountCents int `db:"original_amount_cents"`
InterestRateBps int `db:"interest_rate_bps"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
IsPaidOff bool `db:"is_paid_off"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
SpaceID string `db:"space_id"`
Name string `db:"name"`
Description string `db:"description"`
OriginalAmount decimal.Decimal `db:"original_amount"`
OriginalAmountCents int `db:"original_amount_cents"` // deprecated: kept for SELECT * compatibility
InterestRateBps int `db:"interest_rate_bps"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
IsPaidOff bool `db:"is_paid_off"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type LoanWithPaymentSummary struct {
Loan
TotalPaidCents int
RemainingCents int
ReceiptCount int
TotalPaid decimal.Decimal
Remaining decimal.Decimal
ReceiptCount int
}

17
internal/model/money.go Normal file
View file

@ -0,0 +1,17 @@
package model
import (
"fmt"
"github.com/shopspring/decimal"
)
// FormatMoney formats a decimal as a dollar string like "$12.50"
func FormatMoney(d decimal.Decimal) string {
return fmt.Sprintf("$%s", d.StringFixed(2))
}
// FormatDecimal formats a decimal for form input values like "12.50"
func FormatDecimal(d decimal.Decimal) string {
return d.StringFixed(2)
}

View file

@ -1,6 +1,10 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type TransferDirection string
@ -21,7 +25,8 @@ type MoneyAccount struct {
type AccountTransfer struct {
ID string `db:"id"`
AccountID string `db:"account_id"`
AmountCents int `db:"amount_cents"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
Direction TransferDirection `db:"direction"`
Note string `db:"note"`
RecurringDepositID *string `db:"recurring_deposit_id"`
@ -31,7 +36,7 @@ type AccountTransfer struct {
type MoneyAccountWithBalance struct {
MoneyAccount
BalanceCents int
Balance decimal.Decimal
}
type AccountTransferWithAccount struct {

View file

@ -1,6 +1,10 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type FundingSourceType string
@ -10,16 +14,17 @@ const (
)
type Receipt struct {
ID string `db:"id"`
LoanID string `db:"loan_id"`
SpaceID string `db:"space_id"`
Description string `db:"description"`
TotalAmountCents int `db:"total_amount_cents"`
Date time.Time `db:"date"`
RecurringReceiptID *string `db:"recurring_receipt_id"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
LoanID string `db:"loan_id"`
SpaceID string `db:"space_id"`
Description string `db:"description"`
TotalAmount decimal.Decimal `db:"total_amount"`
TotalAmountCents int `db:"total_amount_cents"` // deprecated: kept for SELECT * compatibility
Date time.Time `db:"date"`
RecurringReceiptID *string `db:"recurring_receipt_id"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type ReceiptFundingSource struct {
@ -27,7 +32,8 @@ type ReceiptFundingSource struct {
ReceiptID string `db:"receipt_id"`
SourceType FundingSourceType `db:"source_type"`
AccountID *string `db:"account_id"`
AmountCents int `db:"amount_cents"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
LinkedExpenseID *string `db:"linked_expense_id"`
LinkedTransferID *string `db:"linked_transfer_id"`
}

View file

@ -1,21 +1,26 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type RecurringDeposit struct {
ID string `db:"id"`
SpaceID string `db:"space_id"`
AccountID string `db:"account_id"`
AmountCents int `db:"amount_cents"`
Frequency Frequency `db:"frequency"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
NextOccurrence time.Time `db:"next_occurrence"`
IsActive bool `db:"is_active"`
Title string `db:"title"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
SpaceID string `db:"space_id"`
AccountID string `db:"account_id"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
Frequency Frequency `db:"frequency"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
NextOccurrence time.Time `db:"next_occurrence"`
IsActive bool `db:"is_active"`
Title string `db:"title"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type RecurringDepositWithAccount struct {

View file

@ -1,6 +1,10 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type Frequency string
@ -13,20 +17,21 @@ const (
)
type RecurringExpense struct {
ID string `db:"id"`
SpaceID string `db:"space_id"`
CreatedBy string `db:"created_by"`
Description string `db:"description"`
AmountCents int `db:"amount_cents"`
Type ExpenseType `db:"type"`
PaymentMethodID *string `db:"payment_method_id"`
Frequency Frequency `db:"frequency"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
NextOccurrence time.Time `db:"next_occurrence"`
IsActive bool `db:"is_active"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
SpaceID string `db:"space_id"`
CreatedBy string `db:"created_by"`
Description string `db:"description"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
Type ExpenseType `db:"type"`
PaymentMethodID *string `db:"payment_method_id"`
Frequency Frequency `db:"frequency"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
NextOccurrence time.Time `db:"next_occurrence"`
IsActive bool `db:"is_active"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type RecurringExpenseWithTags struct {

View file

@ -1,21 +1,26 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type RecurringReceipt struct {
ID string `db:"id"`
LoanID string `db:"loan_id"`
SpaceID string `db:"space_id"`
Description string `db:"description"`
TotalAmountCents int `db:"total_amount_cents"`
Frequency Frequency `db:"frequency"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
NextOccurrence time.Time `db:"next_occurrence"`
IsActive bool `db:"is_active"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID string `db:"id"`
LoanID string `db:"loan_id"`
SpaceID string `db:"space_id"`
Description string `db:"description"`
TotalAmount decimal.Decimal `db:"total_amount"`
TotalAmountCents int `db:"total_amount_cents"` // deprecated: kept for SELECT * compatibility
Frequency Frequency `db:"frequency"`
StartDate time.Time `db:"start_date"`
EndDate *time.Time `db:"end_date"`
NextOccurrence time.Time `db:"next_occurrence"`
IsActive bool `db:"is_active"`
CreatedBy string `db:"created_by"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
type RecurringReceiptSource struct {
@ -23,7 +28,8 @@ type RecurringReceiptSource struct {
RecurringReceiptID string `db:"recurring_receipt_id"`
SourceType FundingSourceType `db:"source_type"`
AccountID *string `db:"account_id"`
AmountCents int `db:"amount_cents"`
Amount decimal.Decimal `db:"amount"`
AmountCents int `db:"amount_cents"` // deprecated: kept for SELECT * compatibility
}
type RecurringReceiptWithSources struct {

View file

@ -1,15 +1,19 @@
package model
import "time"
import (
"time"
"github.com/shopspring/decimal"
)
type DailySpending struct {
Date time.Time `db:"date"`
TotalCents int `db:"total_cents"`
Date time.Time `db:"date"`
Total decimal.Decimal `db:"total"`
}
type MonthlySpending struct {
Month string `db:"month"`
TotalCents int `db:"total_cents"`
Month string `db:"month"`
Total decimal.Decimal `db:"total"`
}
type SpendingReport struct {
@ -17,7 +21,7 @@ type SpendingReport struct {
DailySpending []*DailySpending
MonthlySpending []*MonthlySpending
TopExpenses []*ExpenseWithTagsAndMethod
TotalIncome int
TotalExpenses int
NetBalance int
TotalIncome decimal.Decimal
TotalExpenses decimal.Decimal
NetBalance decimal.Decimal
}