package handlers import ( "net/http" "github.com/gin-gonic/gin" "github.com/google/uuid" "go.uber.org/zap" "rmser/internal/domain/account" "rmser/internal/domain/catalog" "rmser/pkg/logger" ) type SettingsHandler struct { accountRepo account.Repository catalogRepo catalog.Repository } func NewSettingsHandler(accRepo account.Repository, catRepo catalog.Repository) *SettingsHandler { return &SettingsHandler{ accountRepo: accRepo, catalogRepo: catRepo, } } // GetSettings возвращает настройки активного сервера func (h *SettingsHandler) GetSettings(c *gin.Context) { userID := c.MustGet("userID").(uuid.UUID) server, err := h.accountRepo.GetActiveServer(userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if server == nil { c.JSON(http.StatusNotFound, gin.H{"error": "No active server"}) return } c.JSON(http.StatusOK, server) } // UpdateSettingsDTO type UpdateSettingsDTO struct { Name string `json:"name"` DefaultStoreID string `json:"default_store_id"` RootGroupID string `json:"root_group_id"` AutoProcess bool `json:"auto_process"` } // UpdateSettings сохраняет настройки func (h *SettingsHandler) UpdateSettings(c *gin.Context) { userID := c.MustGet("userID").(uuid.UUID) var req UpdateSettingsDTO if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } server, err := h.accountRepo.GetActiveServer(userID) if err != nil || server == nil { c.JSON(http.StatusNotFound, gin.H{"error": "No active server"}) return } // Обновляем поля if req.Name != "" { server.Name = req.Name } server.AutoProcess = req.AutoProcess if req.DefaultStoreID != "" { if uid, err := uuid.Parse(req.DefaultStoreID); err == nil { server.DefaultStoreID = &uid } } else { server.DefaultStoreID = nil } // Теперь правильно ловим ID группы if req.RootGroupID != "" { if uid, err := uuid.Parse(req.RootGroupID); err == nil { server.RootGroupGUID = &uid } } else { server.RootGroupGUID = nil } if err := h.accountRepo.SaveServer(server); err != nil { logger.Log.Error("Failed to save settings", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, server) } // --- Group Tree Logic --- type GroupNode struct { Key string `json:"key"` // ID for Ant Design TreeSelect Value string `json:"value"` // ID value Title string `json:"title"` // Name Children []*GroupNode `json:"children"` // Sub-groups } // GetGroupsTree возвращает иерархию групп func (h *SettingsHandler) GetGroupsTree(c *gin.Context) { userID := c.MustGet("userID").(uuid.UUID) server, err := h.accountRepo.GetActiveServer(userID) if err != nil || server == nil { c.JSON(http.StatusNotFound, gin.H{"error": "No active server"}) return } groups, err := h.catalogRepo.GetGroups(server.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } tree := buildTree(groups) c.JSON(http.StatusOK, tree) } func buildTree(flat []catalog.Product) []*GroupNode { // 1. Map ID -> Node nodeMap := make(map[uuid.UUID]*GroupNode) for _, g := range flat { nodeMap[g.ID] = &GroupNode{ Key: g.ID.String(), Value: g.ID.String(), Title: g.Name, Children: make([]*GroupNode, 0), } } var roots []*GroupNode // 2. Build Hierarchy for _, g := range flat { node := nodeMap[g.ID] if g.ParentID != nil { if parent, exists := nodeMap[*g.ParentID]; exists { parent.Children = append(parent.Children, node) } else { // Если родителя нет в списке (например, он удален или мы выбрали подмножество), // считаем узлом верхнего уровня roots = append(roots, node) } } else { roots = append(roots, node) } } return roots }