Files
boc/backend/handlers/landvex.go
T
Bernt 78b57273e2 security: Add proper authentication, RBAC, and tenant isolation
- Add password hashing with bcrypt
- Add AuthService with proper login
- Add password strength validation
- Add RBAC middleware (AdminOnly, ManagerOrAdmin)
- Add tenant isolation middleware
- Update CRM handler with tenant filtering
- Add JWT fallback for development mode
- Add user context helpers
- Build successful
2026-08-10 12:52:48 +00:00

248 lines
6.8 KiB
Go

package handlers
import (
"database/sql"
"net/http"
"time"
"github.com/go-chi/chi/v5"
)
// LandvexHandler hanterar Landvex bolagskontroll
type LandvexHandler struct {
DB *sql.DB
}
// NewLandvexHandler skapar en ny handler
func NewLandvexHandler(db *sql.DB) *LandvexHandler {
return &LandvexHandler{DB: db}
}
// Entity representerar en juridisk enhet
type Entity struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
OrgNumber string `json:"org_number"`
Country string `json:"country"`
City string `json:"city"`
Address string `json:"address"`
Status string `json:"status"`
FoundedAt time.Time `json:"founded_at"`
ParentID *string `json:"parent_id,omitempty"`
Ownership float64 `json:"ownership_percent"`
CEO string `json:"ceo"`
BoardMembers []Person `json:"board_members"`
Employees int `json:"employees"`
Revenue float64 `json:"revenue"`
Currency string `json:"currency"`
TaxStatus string `json:"tax_status"`
ComplianceStatus string `json:"compliance_status"`
}
// Person representerar en person
type Person struct {
ID string `json:"id"`
Name string `json:"name"`
Role string `json:"role"`
Email string `json:"email"`
Phone string `json:"phone"`
Nationality string `json:"nationality"`
Since string `json:"since"`
}
// Document representerar ett dokument
type Document struct {
ID string `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
EntityID string `json:"entity_id"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
SignedBy []string `json:"signed_by"`
URL string `json:"url"`
}
// ComplianceItem representerar ett compliance-krav
type ComplianceItem struct {
ID string `json:"id"`
EntityID string `json:"entity_id"`
Title string `json:"title"`
Type string `json:"type"`
Status string `json:"status"`
DueDate time.Time `json:"due_date"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
Responsible string `json:"responsible"`
Priority string `json:"priority"`
}
// GetEntities returnerar alla Landvex-enheter från databasen
func (h *LandvexHandler) GetEntities(w http.ResponseWriter, r *http.Request) {
rows, err := h.DB.Query(`
SELECT entity_id, name, jurisdiction, entity_type, status
FROM boc_landvex_entities
WHERE status = 'active'
ORDER BY name
`)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
var entities []Entity
for rows.Next() {
var e Entity
if err := rows.Scan(&e.ID, &e.Name, &e.Country, &e.Type, &e.Status); err != nil {
continue
}
entities = append(entities, e)
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"entities": entities,
})
}
// GetEntity returnerar en specifik enhet
func (h *LandvexHandler) GetEntity(w http.ResponseWriter, r *http.Request) {
entityID := chi.URLParam(r, "id")
var e Entity
err := h.DB.QueryRow(`
SELECT entity_id, name, jurisdiction, entity_type, status
FROM boc_landvex_entities
WHERE entity_id = $1
`, entityID).Scan(&e.ID, &e.Name, &e.Country, &e.Type, &e.Status)
if err != nil {
writeError(w, http.StatusNotFound, "entity not found")
return
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"entity": e,
})
}
// GetDocuments returnerar alla dokument
func (h *LandvexHandler) GetDocuments(w http.ResponseWriter, r *http.Request) {
documents := []Document{
{
ID: "doc-001",
Title: "Styrelseprotokoll 2026-01-15",
Type: "board_minutes",
EntityID: "lvx-ab",
Status: "signed",
CreatedAt: time.Now().Add(-180 * 24 * time.Hour),
SignedBy: []string{"Erik Svensson", "Johan Berglund"},
URL: "/docs/board-2026-01-15.pdf",
},
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"documents": documents,
})
}
// GetCompliance returnerar compliance-krav från databasen
func (h *LandvexHandler) GetCompliance(w http.ResponseWriter, r *http.Request) {
rows, err := h.DB.Query(`
SELECT id, entity_id, category, title, status, due_date, completed_at, notes
FROM boc_landvex_compliance
ORDER BY due_date ASC
`)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
var items []ComplianceItem
for rows.Next() {
var c ComplianceItem
var notes sql.NullString
if err := rows.Scan(&c.ID, &c.EntityID, &c.Type, &c.Title, &c.Status, &c.DueDate, &c.CompletedAt, &notes); err != nil {
continue
}
items = append(items, c)
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"compliance_items": items,
"summary": map[string]interface{}{
"total": len(items),
"pending": countByStatus(items, "pending"),
"overdue": countByStatus(items, "overdue"),
"completed": countByStatus(items, "completed"),
"this_quarter": len(items),
},
})
}
// GetOwnership returnerar ägarstruktur från databasen
func (h *LandvexHandler) GetOwnership(w http.ResponseWriter, r *http.Request) {
rows, err := h.DB.Query(`
SELECT e.entity_id, e.name, e.jurisdiction, e.entity_type,
o.owner_name, o.ownership_percent, o.parent_entity_id
FROM boc_landvex_entities e
LEFT JOIN boc_landvex_ownership o ON e.entity_id = o.entity_id
WHERE e.status = 'active'
ORDER BY e.name
`)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
var entities []map[string]interface{}
for rows.Next() {
var entityID, name, jurisdiction, entityType, ownerName string
var ownership float64
var parentID sql.NullString
if err := rows.Scan(&entityID, &name, &jurisdiction, &entityType, &ownerName, &ownership, &parentID); err != nil {
continue
}
entities = append(entities, map[string]interface{}{
"id": entityID,
"name": name,
"jurisdiction": jurisdiction,
"type": entityType,
"owner": ownerName,
"ownership": ownership,
})
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"ownership": map[string]interface{}{
"structure": "linear",
"ultimate_beneficial_owner": map[string]interface{}{
"name": "Erik Svensson",
"nationality": "SE",
"ownership": 100,
},
"entities": entities,
},
})
}
func countByStatus(items []ComplianceItem, status string) int {
count := 0
for _, item := range items {
if item.Status == status {
count++
}
}
return count
}
func strPtr(s string) *string {
return &s
}