paisa/internal/server/ledger.go

83 lines
2.4 KiB
Go
Raw Normal View History

2022-04-09 12:45:05 -04:00
package server
import (
2022-04-10 12:13:03 -04:00
"strings"
2022-04-09 12:45:05 -04:00
"time"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
2022-04-14 03:17:42 -04:00
"github.com/ChizhovVadim/xirr"
2022-04-09 12:45:05 -04:00
"github.com/ananthakumaran/paisa/internal/model/posting"
"github.com/ananthakumaran/paisa/internal/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
2022-04-10 12:13:03 -04:00
type Breakdown struct {
Group string `json:"group"`
Amount float64 `json:"amount"`
MarketAmount float64 `json:"market_amount"`
2022-04-14 03:17:42 -04:00
XIRR float64 `json:"xirr"`
2022-04-10 12:13:03 -04:00
}
2022-04-09 12:45:05 -04:00
func GetLedger(db *gorm.DB) gin.H {
var postings []posting.Posting
result := db.Order("date DESC").Find(&postings)
if result.Error != nil {
log.Fatal(result.Error)
}
date := time.Now()
postings = lo.Map(postings, func(p posting.Posting, _ int) posting.Posting {
p.MarketAmount = service.GetMarketPrice(db, p, date)
return p
})
breakdowns := computeBreakdown(db, lo.Filter(postings, func(p posting.Posting, _ int) bool { return strings.HasPrefix(p.Account, "Asset:") }))
2022-04-10 12:13:03 -04:00
return gin.H{"postings": postings, "breakdowns": breakdowns}
}
func computeBreakdown(db *gorm.DB, postings []posting.Posting) map[string]Breakdown {
2022-04-14 03:17:42 -04:00
accounts := make(map[string]bool)
for _, p := range postings {
var parts []string
for _, part := range strings.Split(p.Account, ":") {
parts = append(parts, part)
accounts[strings.Join(parts, ":")] = true
2022-04-10 12:13:03 -04:00
}
}
2022-04-14 03:17:42 -04:00
today := time.Now()
result := make(map[string]Breakdown)
for group := range accounts {
ps := lo.Filter(postings, func(p posting.Posting, _ int) bool { return strings.HasPrefix(p.Account, group) })
amount := lo.Reduce(ps, func(acc float64, p posting.Posting, _ int) float64 {
if service.IsInterest(db, p) {
return acc
} else {
return acc + p.Amount
}
}, 0.0)
2022-04-10 12:13:03 -04:00
marketAmount := lo.Reduce(ps, func(acc float64, p posting.Posting, _ int) float64 { return acc + p.MarketAmount }, 0.0)
payments := lo.Reverse(lo.Map(ps, func(p posting.Posting, _ int) xirr.Payment {
if service.IsInterest(db, p) {
return xirr.Payment{Date: p.Date, Amount: 0}
} else {
return xirr.Payment{Date: p.Date, Amount: -p.Amount}
}
}))
2022-04-14 03:17:42 -04:00
payments = append(payments, xirr.Payment{Date: today, Amount: marketAmount})
returns, err := xirr.XIRR(payments)
if err != nil {
log.Fatal(err)
2022-04-10 12:13:03 -04:00
}
2022-04-14 03:17:42 -04:00
breakdown := Breakdown{Amount: amount, MarketAmount: marketAmount, XIRR: (returns - 1) * 100, Group: group}
result[group] = breakdown
2022-04-10 12:13:03 -04:00
}
return result
2022-04-09 12:45:05 -04:00
}