package repository import ( "context" "database/sql" "encoding/json" "fmt" "erp-mvp/core-service/internal/models" "github.com/google/uuid" ) type LocationRepository interface { Create(ctx context.Context, location *models.StorageLocation) error GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.StorageLocation, error) GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.StorageLocation, error) Update(ctx context.Context, location *models.StorageLocation) error Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error GetChildren(ctx context.Context, parentID uuid.UUID, orgID uuid.UUID) ([]*models.StorageLocation, error) } type locationRepository struct { db *sql.DB } func NewLocationRepository(db *sql.DB) LocationRepository { return &locationRepository{db: db} } func (r *locationRepository) Create(ctx context.Context, location *models.StorageLocation) error { query := ` INSERT INTO storage_locations (id, organization_id, parent_id, name, address, type, coordinates, created_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ` // Конвертируем JSON в строку var coordinatesJSON string if location.Coordinates != nil { coords, err := json.Marshal(location.Coordinates) if err != nil { return fmt.Errorf("failed to marshal coordinates: %w", err) } coordinatesJSON = string(coords) } _, err := r.db.ExecContext(ctx, query, location.ID, location.OrganizationID, location.ParentID, location.Name, location.Address, location.Type, coordinatesJSON, location.CreatedAt, ) if err != nil { return fmt.Errorf("failed to create storage location: %w", err) } return nil } func (r *locationRepository) GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.StorageLocation, error) { query := ` SELECT id, organization_id, parent_id, name, address, type, coordinates, created_at FROM storage_locations WHERE id = $1 AND organization_id = $2 ` var coordinatesJSON []byte location := &models.StorageLocation{} err := r.db.QueryRowContext(ctx, query, id, orgID).Scan( &location.ID, &location.OrganizationID, &location.ParentID, &location.Name, &location.Address, &location.Type, &coordinatesJSON, &location.CreatedAt, ) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("storage location not found") } return nil, fmt.Errorf("failed to get storage location: %w", err) } // Конвертируем JSON строку в map if len(coordinatesJSON) > 0 { err = json.Unmarshal(coordinatesJSON, &location.Coordinates) if err != nil { return nil, fmt.Errorf("failed to unmarshal coordinates: %w", err) } } else { location.Coordinates = make(models.JSON) } return location, nil } func (r *locationRepository) GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.StorageLocation, error) { query := ` SELECT id, organization_id, parent_id, name, address, type, coordinates, created_at FROM storage_locations WHERE organization_id = $1 ORDER BY name ` rows, err := r.db.QueryContext(ctx, query, orgID) if err != nil { return nil, fmt.Errorf("failed to query storage locations: %w", err) } defer rows.Close() var locations []*models.StorageLocation for rows.Next() { var coordinatesJSON []byte location := &models.StorageLocation{} err := rows.Scan( &location.ID, &location.OrganizationID, &location.ParentID, &location.Name, &location.Address, &location.Type, &coordinatesJSON, &location.CreatedAt, ) if err != nil { return nil, fmt.Errorf("failed to scan storage location: %w", err) } // Конвертируем JSON строку в map if len(coordinatesJSON) > 0 { err = json.Unmarshal(coordinatesJSON, &location.Coordinates) if err != nil { return nil, fmt.Errorf("failed to unmarshal coordinates: %w", err) } } else { location.Coordinates = make(models.JSON) } locations = append(locations, location) } if err = rows.Err(); err != nil { return nil, fmt.Errorf("error iterating storage locations: %w", err) } return locations, nil } func (r *locationRepository) Update(ctx context.Context, location *models.StorageLocation) error { query := ` UPDATE storage_locations SET parent_id = $3, name = $4, address = $5, type = $6, coordinates = $7 WHERE id = $1 AND organization_id = $2 ` // Конвертируем JSON в строку var coordinatesJSON string if location.Coordinates != nil { coords, err := json.Marshal(location.Coordinates) if err != nil { return fmt.Errorf("failed to marshal coordinates: %w", err) } coordinatesJSON = string(coords) } result, err := r.db.ExecContext(ctx, query, location.ID, location.OrganizationID, location.ParentID, location.Name, location.Address, location.Type, coordinatesJSON, ) if err != nil { return fmt.Errorf("failed to update storage location: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rowsAffected == 0 { return fmt.Errorf("storage location not found") } return nil } func (r *locationRepository) Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error { query := ` DELETE FROM storage_locations WHERE id = $1 AND organization_id = $2 ` result, err := r.db.ExecContext(ctx, query, id, orgID) if err != nil { return fmt.Errorf("failed to delete storage location: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rowsAffected == 0 { return fmt.Errorf("storage location not found") } return nil } func (r *locationRepository) GetChildren(ctx context.Context, parentID uuid.UUID, orgID uuid.UUID) ([]*models.StorageLocation, error) { query := ` SELECT id, organization_id, parent_id, name, address, type, coordinates, created_at FROM storage_locations WHERE parent_id = $1 AND organization_id = $2 ORDER BY name ` rows, err := r.db.QueryContext(ctx, query, parentID, orgID) if err != nil { return nil, fmt.Errorf("failed to query child locations: %w", err) } defer rows.Close() var locations []*models.StorageLocation for rows.Next() { var coordinatesJSON []byte location := &models.StorageLocation{} err := rows.Scan( &location.ID, &location.OrganizationID, &location.ParentID, &location.Name, &location.Address, &location.Type, &coordinatesJSON, &location.CreatedAt, ) if err != nil { return nil, fmt.Errorf("failed to scan child location: %w", err) } // Конвертируем JSON строку в map if len(coordinatesJSON) > 0 { err = json.Unmarshal(coordinatesJSON, &location.Coordinates) if err != nil { return nil, fmt.Errorf("failed to unmarshal coordinates: %w", err) } } else { location.Coordinates = make(models.JSON) } locations = append(locations, location) } if err = rows.Err(); err != nil { return nil, fmt.Errorf("error iterating child locations: %w", err) } return locations, nil }