This repository was archived by the owner on May 26, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathledger.go
More file actions
109 lines (94 loc) · 3.09 KB
/
ledger.go
File metadata and controls
109 lines (94 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"fmt"
"time"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
// Entry represents a ledger entry in the database
type Entry struct {
ID uint `gorm:"primaryKey"`
AccountID string `gorm:"column:account_id;not null;index:idx_account_asset_symbol;index:idx_account_participant"`
AccountType AccountType `gorm:"column:account_type;not null"`
AssetSymbol string `gorm:"column:asset_symbol;not null;index:idx_account_asset_symbol"`
Participant string `gorm:"column:participant;not null;index:idx_account_participant"`
Credit decimal.Decimal `gorm:"column:credit;type:decimal(38,18);not null"`
Debit decimal.Decimal `gorm:"column:debit;type:decimal(38,18);not null"`
CreatedAt time.Time
}
func (Entry) TableName() string {
return "ledger"
}
type ParticipantLedger struct {
participant string
db *gorm.DB
}
func GetParticipantLedger(db *gorm.DB, participant string) *ParticipantLedger {
return &ParticipantLedger{participant: participant, db: db}
}
func (l *ParticipantLedger) Record(accountID string, assetSymbol string, amount decimal.Decimal) error {
entry := &Entry{
AccountID: accountID,
Participant: l.participant,
AssetSymbol: assetSymbol,
Credit: decimal.Zero,
Debit: decimal.Zero,
CreatedAt: time.Now(),
}
if amount.IsPositive() {
entry.Credit = amount
} else if amount.IsNegative() {
entry.Debit = amount.Abs()
} else {
return nil
}
fmt.Println("recording entry for: ", l.participant, " in account ", accountID, " ", assetSymbol, " ", amount)
return l.db.Create(entry).Error
}
func (l *ParticipantLedger) Balance(accountID string, assetSymbol string) (decimal.Decimal, error) {
type result struct {
Balance decimal.Decimal `gorm:"column:balance"`
}
var res result
if err := l.db.Model(&Entry{}).
Where("account_id = ? AND asset_symbol = ? AND participant = ?", accountID, assetSymbol, l.participant).
Select("COALESCE(SUM(credit),0) - COALESCE(SUM(debit),0) AS balance").
Scan(&res).Error; err != nil {
return decimal.Zero, err
}
return res.Balance, nil
}
func (l *ParticipantLedger) GetBalances(accountID string) ([]Balance, error) {
type row struct {
Asset string `gorm:"column:asset_symbol"`
Balance decimal.Decimal `gorm:"column:balance"`
}
var rows []row
if err := l.db.
Model(&Entry{}).
Where("account_id = ? AND participant = ?", accountID, l.participant).
Select("asset_symbol", "COALESCE(SUM(credit),0) - COALESCE(SUM(debit),0) AS balance").
Group("asset_symbol").
Scan(&rows).Error; err != nil {
return nil, err
}
balances := make([]Balance, len(rows))
for i, r := range rows {
balances[i] = Balance{
Asset: r.Asset,
Amount: r.Balance,
}
}
return balances, nil
}
func (l *ParticipantLedger) GetEntries(accountID, assetSymbol string) ([]Entry, error) {
var entries []Entry
q := l.db.Where("account_id = ? AND participant = ?", accountID, l.participant)
if assetSymbol != "" {
q = q.Where("asset_symbol = ?", assetSymbol)
}
if err := q.Find(&entries).Error; err != nil {
return nil, err
}
return entries, nil
}