package models import ( "time" "gorm.io/gorm" ) // DefaultCategory represents a category template for new user initialization // These templates are copied to users' categories table when they first access categories type DefaultCategory struct { ID uint `gorm:"primarykey" json:"id"` Name string `gorm:"size:50;not null" json:"name"` Icon string `gorm:"size:100" json:"icon"` // Iconify format: mdi:icon-name Color string `gorm:"size:20" json:"color"` // HEX color code (e.g., #FF6B35) Type CategoryType `gorm:"size:20;not null" json:"type"` // income or expense ParentID *uint `gorm:"index" json:"parent_id,omitempty"` SortOrder int `gorm:"default:0" json:"sort_order"` IsActive bool `gorm:"default:true" json:"is_active"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` // Relationships Parent *DefaultCategory `gorm:"foreignKey:ParentID" json:"parent,omitempty"` Children []DefaultCategory `gorm:"foreignKey:ParentID" json:"children,omitempty"` } // TableName specifies the table name for DefaultCategory func (DefaultCategory) TableName() string { return "default_categories" } // GetAllDefaultCategories retrieves all active default categories from the database func GetAllDefaultCategories(db *gorm.DB) ([]DefaultCategory, error) { var categories []DefaultCategory err := db.Where("is_active = ?", true).Order("sort_order ASC").Find(&categories).Error return categories, err } // GetDefaultCategoriesWithChildren retrieves all active root categories with their children func GetDefaultCategoriesWithChildren(db *gorm.DB) ([]DefaultCategory, error) { var categories []DefaultCategory err := db.Where("is_active = ? AND parent_id IS NULL", true). Preload("Children", "is_active = ?", true). Order("sort_order ASC"). Find(&categories).Error return categories, err } // CopyToUserCategories copies default categories to a user's categories // Returns a map of old DefaultCategory ID to new Category ID for parent-child mapping func CopyDefaultCategoriesToUser(db *gorm.DB, userID uint) error { // Get all default categories var defaults []DefaultCategory if err := db.Where("is_active = ?", true).Order("sort_order ASC").Find(&defaults).Error; err != nil { return err } if len(defaults) == 0 { return nil // No default categories to copy } // Map to track old ID -> new ID for parent references idMap := make(map[uint]uint) // First pass: create all root categories (no parent) for _, dc := range defaults { if dc.ParentID == nil { cat := Category{ UserID: userID, Name: dc.Name, Icon: dc.Icon, Color: dc.Color, Type: dc.Type, ParentID: nil, SortOrder: dc.SortOrder, } if err := db.Create(&cat).Error; err != nil { return err } idMap[dc.ID] = cat.ID } } // Second pass: create all child categories for _, dc := range defaults { if dc.ParentID != nil { newParentID := idMap[*dc.ParentID] cat := Category{ UserID: userID, Name: dc.Name, Icon: dc.Icon, Color: dc.Color, Type: dc.Type, ParentID: &newParentID, SortOrder: dc.SortOrder, } if err := db.Create(&cat).Error; err != nil { return err } idMap[dc.ID] = cat.ID } } return nil }