package handlers import ( "encoding/json" "net/http" "os" "time" ) func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } var ledgerBaseURL = getEnv("LEDGER_URL", "http://172.17.0.1:3250") // LedgerClient handles communication with aamos-ledger type LedgerClient struct { BaseURL string } func NewLedgerClient() *LedgerClient { return &LedgerClient{BaseURL: ledgerBaseURL} } func (c *LedgerClient) Get(path string) (*http.Response, error) { return http.Get(c.BaseURL + path) } // LedgerFinanceHandler connects to aamos-ledger for financial data type LedgerFinanceHandler struct { Client *LedgerClient } func NewLedgerFinanceHandler() *LedgerFinanceHandler { return &LedgerFinanceHandler{Client: NewLedgerClient()} } // GetBalanceSheet returns trial balance from ledger func (h *LedgerFinanceHandler) GetBalanceSheet(w http.ResponseWriter, r *http.Request) { period := r.URL.Query().Get("period") if period == "" { period = time.Now().Format("2006-01") } resp, err := h.Client.Get("/api/ledger/trial-balance?period=" + period) if err != nil || resp.StatusCode != 200 { // Fallback to mock data w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "assets": []map[string]interface{}{ {"account": "1930 - Checkkonto", "amount": 245000}, {"account": "1940 - Sparkonto", "amount": 500000}, {"account": "1510 - Kundfordringar", "amount": 125000}, }, "liabilities": []map[string]interface{}{ {"account": "2440 - Leverantörsskulder", "amount": 85000}, {"account": "2013 - Aktiekapital", "amount": 100000}, }, "equity": []map[string]interface{}{ {"account": "2091 - Balanserad vinst", "amount": 485000}, }, "total_assets": 870000, "total_liabilities": 185000, "total_equity": 685000, "period": period, }) return } defer resp.Body.Close() var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { writeError(w, http.StatusInternalServerError, "decode error") return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) } // GetIncomeStatement returns income statement (not yet implemented in ledger) func (h *LedgerFinanceHandler) GetIncomeStatement(w http.ResponseWriter, r *http.Request) { // Return mock data until ledger implements this w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "revenue": 245000, "expenses": 180000, "net_income": 65000, "period": time.Now().Format("2006-01"), }) } // GetMomsReport returns VAT report (not yet implemented in ledger) func (h *LedgerFinanceHandler) GetMomsReport(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "moms_in": 61250, "moms_ut": 35000, "moms_att_betala": 26250, "period": time.Now().Format("2006-01"), }) } // GetAccounts returns chart of accounts from ledger func (h *LedgerFinanceHandler) GetAccounts(w http.ResponseWriter, r *http.Request) { resp, err := h.Client.Get("/api/v1/accounts") if err != nil || resp.StatusCode != 200 { // Fallback to mock data w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "accounts": []map[string]interface{}{ {"id": "1930", "name": "Checkkonto", "type": "asset", "balance": 245000}, {"id": "1940", "name": "Sparkonto", "type": "asset", "balance": 500000}, {"id": "1510", "name": "Kundfordringar", "type": "asset", "balance": 125000}, {"id": "2440", "name": "Leverantörsskulder", "type": "liability", "balance": 85000}, {"id": "2013", "name": "Aktiekapital", "type": "equity", "balance": 100000}, {"id": "2091", "name": "Balanserad vinst", "type": "equity", "balance": 485000}, {"id": "3001", "name": "Försäljning tjänster", "type": "revenue", "balance": 450000}, {"id": "6100", "name": "Löner", "type": "expense", "balance": 180000}, }, }) return } defer resp.Body.Close() var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { var accounts []map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&accounts); err != nil { writeError(w, http.StatusInternalServerError, "decode error") return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{"accounts": accounts}) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(result) } // GetInvoices returns invoices (mock until implemented) func (h *LedgerFinanceHandler) GetInvoices(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "invoices": []map[string]interface{}{ {"id": "INV-001", "customer": "Test AB", "amount": 25000, "status": "paid", "due_date": "2026-07-30"}, {"id": "INV-002", "customer": "Acme Corp", "amount": 45000, "status": "pending", "due_date": "2026-08-15"}, }, "total": 2, }) } // GetCashflow returns cashflow (mock until implemented) func (h *LedgerFinanceHandler) GetCashflow(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "inflow": 320000, "outflow": 180000, "net": 140000, "period": time.Now().Format("2006-01"), }) } // GetBudget returns budget (mock until implemented) func (h *LedgerFinanceHandler) GetBudget(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "budget": 500000, "actual": 245000, "remaining": 255000, "period": time.Now().Format("2006-01"), }) } // CreateExpense creates an expense (mock until implemented) func (h *LedgerFinanceHandler) CreateExpense(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "id": "EXP-001", "status": "created", }) } // ListExpenses lists expenses (mock until implemented) func (h *LedgerFinanceHandler) ListExpenses(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "expenses": []map[string]interface{}{ {"id": "EXP-001", "category": "Boende", "amount": 8500, "date": "2026-07-01"}, {"id": "EXP-002", "category": "Mat", "amount": 3200, "date": "2026-07-05"}, }, "total": 2, }) }