package handlers import ( "encoding/json" "net/http" "strings" ) // AIAccountingHandler hanterar AI-driven bokföringsförslag type AIAccountingHandler struct{} func NewAIAccountingHandler() *AIAccountingHandler { return &AIAccountingHandler{} } // AISuggestion representerar ett AI-förslag type AISuggestion struct { ID string `json:"id"` Description string `json:"description"` SuggestedAccount string `json:"suggested_account"` AccountName string `json:"account_name"` Confidence float64 `json:"confidence"` Debit float64 `json:"debit"` Credit float64 `json:"credit"` Reason string `json:"reason"` } // GetSuggestions returnerar AI-förslag för en transaktion func (h *AIAccountingHandler) GetSuggestions(w http.ResponseWriter, r *http.Request) { var req struct { Description string `json:"description"` Amount float64 `json:"amount"` Counterparty string `json:"counterparty"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]interface{}{ "ok": false, "error": err.Error(), }) return } suggestions := h.analyzeTransaction(req.Description, req.Amount, req.Counterparty) writeJSON(w, http.StatusOK, map[string]interface{}{ "ok": true, "suggestions": suggestions, "input": req, }) } // analyzeTransaction analyserar en transaktion och ger förslag func (h *AIAccountingHandler) analyzeTransaction(description string, amount float64, counterparty string) []AISuggestion { desc := strings.ToLower(description) counter := strings.ToLower(counterparty) var suggestions []AISuggestion // Regelbaserad AI (kan bytas mot ML-modell) switch { case containsAny(desc, []string{"faktura", "inbetalning", "betalning"}) && amount > 0: suggestions = append(suggestions, AISuggestion{ ID: "ai-001", Description: description, SuggestedAccount: "1510", AccountName: "Kundfordringar", Confidence: 0.92, Debit: amount, Credit: 0, Reason: "Positivt belopp med fakturareferens = kundfordran", }) suggestions = append(suggestions, AISuggestion{ ID: "ai-002", Description: description, SuggestedAccount: "3010", AccountName: "Försäljning tjänster", Confidence: 0.88, Debit: 0, Credit: amount, Reason: "Motkonto till kundfordran = försäljning", }) case containsAny(desc, []string{"lön", "salary", "löneutbetalning"}): suggestions = append(suggestions, AISuggestion{ ID: "ai-003", Description: description, SuggestedAccount: "7210", AccountName: "Löner", Confidence: 0.95, Debit: amount, Credit: 0, Reason: "Löneutbetalning = lönekonto", }) suggestions = append(suggestions, AISuggestion{ ID: "ai-004", Description: description, SuggestedAccount: "1930", AccountName: "Företagskonto", Confidence: 0.95, Debit: 0, Credit: amount, Reason: "Lön betalas från företagskonto", }) case containsAny(desc, []string{"aws", "hosting", "server", "cloud"}): suggestions = append(suggestions, AISuggestion{ ID: "ai-005", Description: description, SuggestedAccount: "6540", AccountName: "IT-kostnader", Confidence: 0.89, Debit: amount, Credit: 0, Reason: "AWS/hosting = IT-kostnader", }) case containsAny(desc, []string{"zoomer", "quixzoom", "fältarbetare"}): suggestions = append(suggestions, AISuggestion{ ID: "ai-006", Description: description, SuggestedAccount: "7690", AccountName: "Övriga personalkostnader", Confidence: 0.87, Debit: amount, Credit: 0, Reason: "Zoomer-utbetalning = personalkostnad", }) case containsAny(desc, []string{"försäkring", "insurance"}): suggestions = append(suggestions, AISuggestion{ ID: "ai-007", Description: description, SuggestedAccount: "6310", AccountName: "Försäkringspremier", Confidence: 0.91, Debit: amount, Credit: 0, Reason: "Försäkringsbetalning = försäkringspremie", }) case containsAny(counter, []string{"skatteverket", "skatt"}): suggestions = append(suggestions, AISuggestion{ ID: "ai-008", Description: description, SuggestedAccount: "2012", AccountName: "Skatter", Confidence: 0.94, Debit: amount, Credit: 0, Reason: "Skatteverket = skattebetalning", }) default: // Generiskt förslag baserat på belopp if amount > 0 { suggestions = append(suggestions, AISuggestion{ ID: "ai-099", Description: description, SuggestedAccount: "1930", AccountName: "Företagskonto", Confidence: 0.45, Debit: 0, Credit: amount, Reason: "Kunde inte identifiera — granska manuellt", }) } else { suggestions = append(suggestions, AISuggestion{ ID: "ai-099", Description: description, SuggestedAccount: "6991", AccountName: "Övriga externa kostnader", Confidence: 0.45, Debit: -amount, Credit: 0, Reason: "Kunde inte identifiera — granska manuellt", }) } } return suggestions } func containsAny(s string, substrs []string) bool { for _, substr := range substrs { if strings.Contains(s, substr) { return true } } return false }