Files
boc/backend/ledger/real_client.go
T

143 lines
3.6 KiB
Go
Raw Normal View History

// Package ledger - Real client for aamos-ledger integration
// Uses direct DB connection for reliability
package ledger
import (
"context"
"database/sql"
"fmt"
"time"
_ "github.com/lib/pq"
)
// RealClient connects directly to aamos-ledger database
type RealClient struct {
db *sql.DB
}
// NewRealClient creates a client connected to ledger DB
func NewRealClient(dbURL string) (*RealClient, error) {
db, err := sql.Open("postgres", dbURL)
if err != nil {
return nil, fmt.Errorf("failed to connect to ledger DB: %w", err)
}
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("failed to ping ledger DB: %w", err)
}
return &RealClient{db: db}, nil
}
// Account represents a BAS account
type Account struct {
Code string `json:"code"`
Name string `json:"name"`
AccountType string `json:"account_type"`
Balance float64 `json:"balance"`
}
// GetAccounts returns all BAS accounts
func (c *RealClient) GetAccounts(ctx context.Context) ([]Account, error) {
rows, err := c.db.QueryContext(ctx, `
SELECT a.code, a.name, a.account_type,
COALESCE(SUM(CASE WHEN jl.debit IS NOT NULL THEN jl.debit ELSE 0 END) -
SUM(CASE WHEN jl.credit IS NOT NULL THEN jl.credit ELSE 0 END), 0) as balance
FROM accounts a
LEFT JOIN journal_lines jl ON a.id = jl.account_id
GROUP BY a.id, a.code, a.name, a.account_type
ORDER BY a.code
`)
if err != nil {
return nil, fmt.Errorf("query accounts: %w", err)
}
defer rows.Close()
var accounts []Account
for rows.Next() {
var a Account
if err := rows.Scan(&a.Code, &a.Name, &a.AccountType, &a.Balance); err != nil {
return nil, fmt.Errorf("scan account: %w", err)
}
accounts = append(accounts, a)
}
return accounts, rows.Err()
}
// GetBalanceSheet returns assets, liabilities, equity
func (c *RealClient) GetBalanceSheet(ctx context.Context) (map[string]interface{}, error) {
accounts, err := c.GetAccounts(ctx)
if err != nil {
return nil, err
}
var assets, liabilities, equity []Account
var totalAssets, totalLiabilities, totalEquity float64
for _, a := range accounts {
switch a.AccountType {
case "Asset":
assets = append(assets, a)
totalAssets += a.Balance
case "Liability":
liabilities = append(liabilities, a)
totalLiabilities += a.Balance
case "Equity":
equity = append(equity, a)
totalEquity += a.Balance
}
}
return map[string]interface{}{
"assets": accountsToMaps(assets),
"liabilities": accountsToMaps(liabilities),
"equity": accountsToMaps(equity),
"total_assets": totalAssets,
"total_liabilities": totalLiabilities,
"total_equity": totalEquity,
"period": time.Now().Format("2006-01"),
}, nil
}
// GetTrialBalance returns trial balance
func (c *RealClient) GetTrialBalance(ctx context.Context) ([]map[string]interface{}, error) {
accounts, err := c.GetAccounts(ctx)
if err != nil {
return nil, err
}
var result []map[string]interface{}
for _, a := range accounts {
result = append(result, map[string]interface{}{
"account_number": a.Code,
"account_name": a.Name,
"balance": a.Balance,
"account_type": a.AccountType,
})
}
return result, nil
}
// Close closes the database connection
func (c *RealClient) Close() error {
return c.db.Close()
}
func accountsToMaps(accounts []Account) []map[string]interface{} {
var result []map[string]interface{}
for _, a := range accounts {
result = append(result, map[string]interface{}{
"account": a.Code + " - " + a.Name,
"amount": a.Balance,
})
}
return result
}