package ledger import ( "context" "fmt" "time" "github.com/jackc/pgx/v5/pgxpool" ) // Ledger handles double-entry accounting type Ledger struct { db *pgxpool.Pool } // NewLedger creates a new ledger func NewLedger(db *pgxpool.Pool) *Ledger { return &Ledger{db: db} } // Entry represents a ledger entry type Entry struct { ID string CustomerID string AccountType string // "asset", "liability", "equity" Amount string Currency string Description string Reference string CreatedAt time.Time } // CreateEntry creates a double-entry ledger entry func (l *Ledger) CreateEntry(ctx context.Context, debit, credit *Entry) error { tx, err := l.db.Begin(ctx) if err != nil { return fmt.Errorf("failed to begin transaction: %w", err) } defer tx.Rollback(ctx) // Insert debit entry debitQuery := ` INSERT INTO ledger_entries ( customer_id, account_type, amount, currency, description, reference, side, created_at ) VALUES ($1, $2, $3, $4, $5, $6, 'debit', NOW()) ` _, err = tx.Exec(ctx, debitQuery, debit.CustomerID, debit.AccountType, debit.Amount, debit.Currency, debit.Description, debit.Reference, ) if err != nil { return fmt.Errorf("failed to create debit entry: %w", err) } // Insert credit entry creditQuery := ` INSERT INTO ledger_entries ( customer_id, account_type, amount, currency, description, reference, side, created_at ) VALUES ($1, $2, $3, $4, $5, $6, 'credit', NOW()) ` _, err = tx.Exec(ctx, creditQuery, credit.CustomerID, credit.AccountType, credit.Amount, credit.Currency, credit.Description, credit.Reference, ) if err != nil { return fmt.Errorf("failed to create credit entry: %w", err) } return tx.Commit(ctx) } // GetBalance gets account balance for a customer func (l *Ledger) GetBalance(ctx context.Context, customerID, accountType string) (string, error) { query := ` SELECT SUM(CASE WHEN side = 'debit' THEN amount::numeric ELSE -amount::numeric END) as balance FROM ledger_entries WHERE customer_id = $1 AND account_type = $2 ` var balance string err := l.db.QueryRow(ctx, query, customerID, accountType).Scan(&balance) if err != nil { return "0", nil } return balance, nil }