package statuses import ( "context" "encoding/csv" "fmt" "io" "strings" "inventree/internal/models" ) type ImportResult struct { Created int Updated int Errors []string } // Import creates or updates statuses from CSV data with "Name" and "Color" // columns (case-insensitive header names, Color optional). Existing // statuses are matched and updated by name (case-insensitive); everything // else is created. func (s *Store) Import(ctx context.Context, r io.Reader) (*ImportResult, error) { existing, err := s.List(ctx) if err != nil { return nil, err } byName := map[string]int64{} for _, st := range existing { byName[strings.ToLower(st.Name)] = st.ID } cr := csv.NewReader(r) cr.FieldsPerRecord = -1 header, err := cr.Read() if err != nil { if err == io.EOF { return &ImportResult{}, nil } return nil, fmt.Errorf("read CSV header: %w", err) } colIdx := map[string]int{} for i, h := range header { colIdx[strings.ToLower(strings.TrimSpace(h))] = i } get := func(row []string, key string) string { idx, ok := colIdx[key] if !ok || idx >= len(row) { return "" } return strings.TrimSpace(row[idx]) } result := &ImportResult{} rowNum := 1 for { row, err := cr.Read() if err == io.EOF { break } if err != nil { return nil, fmt.Errorf("read CSV row %d: %w", rowNum, err) } rowNum++ name := get(row, "name") if name == "" { result.Errors = append(result.Errors, fmt.Sprintf("row %d: name is required, skipped", rowNum)) continue } color := get(row, "color") if id, ok := byName[strings.ToLower(name)]; ok { st, err := s.Get(ctx, id) if err != nil { result.Errors = append(result.Errors, fmt.Sprintf("row %d: %v", rowNum, err)) continue } if color != "" { st.Color = color } if err := s.Update(ctx, st); err != nil { result.Errors = append(result.Errors, fmt.Sprintf("row %d: update failed: %v", rowNum, err)) continue } result.Updated++ continue } st := &models.Status{Name: name, Color: color} if err := s.Create(ctx, st); err != nil { result.Errors = append(result.Errors, fmt.Sprintf("row %d: create failed: %v", rowNum, err)) continue } byName[strings.ToLower(name)] = st.ID result.Created++ } return result, nil }