package domain import ( "context" "fmt" "time" "github.com/lib/pq" "gorm.io/datatypes" ) // ServiceType defines the type of service type ServiceType string const ( ServiceTypeMaintenance ServiceType = "maintenance" ServiceTypeConsulting ServiceType = "consulting" ServiceTypeTransport ServiceType = "transport" ServiceTypeInspection ServiceType = "inspection" ServiceTypeTraining ServiceType = "training" ServiceTypeRepair ServiceType = "repair" ServiceTypeOther ServiceType = "other" ) // Service represents a service offered by an organization (database entity) // Note: There's also a ServiceJSON struct in organization.go for API serialization type Service struct { ID string `gorm:"primaryKey;type:text"` Type ServiceType `gorm:"not null;type:varchar(50);index"` Domain string `gorm:"not null;type:text;index"` // Service domain (compressors, HVAC, etc.) Description string `gorm:"type:text"` OnSite bool `gorm:"not null;default:false"` // Whether service is performed on-site HourlyRate float64 `gorm:"type:decimal(10,2)"` // € per hour ServiceAreaKm float64 `gorm:"type:decimal(8,2)"` // Service area radius in km Certifications datatypes.JSON `gorm:"default:'[]'"` // []string // Business information OrganizationID string `gorm:"not null;type:text;index"` Organization *Organization `gorm:"foreignKey:OrganizationID"` // Site information (for location-based matching) SiteID *string `gorm:"type:text;index"` Site *Site `gorm:"foreignKey:SiteID"` // Service location (PostGIS Point for spatial queries) ServiceLocation Point `gorm:"type:geometry(Point,4326)"` // PostGIS geometry point // Discovery and search fields SearchKeywords string `gorm:"type:text"` // Full-text search keywords Tags pq.StringArray `gorm:"type:text[]"` // Searchable tags array AvailabilityStatus string `gorm:"type:varchar(20);default:'available';index"` // available, limited, unavailable AvailabilitySchedule datatypes.JSON `gorm:"type:jsonb"` // Time-based availability schedule // Additional metadata ResponseTime string `gorm:"type:text"` // Response time SLA Warranty string `gorm:"type:text"` // Warranty terms Specializations datatypes.JSON `gorm:"type:jsonb;default:'[]'"` // []string - specific specializations Availability string `gorm:"type:text"` // Service availability (legacy field, kept for compatibility) Sources datatypes.JSON `gorm:"type:jsonb"` // Data sources // Timestamps CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` } // TableName specifies the table name for GORM func (Service) TableName() string { return "services" } // ServiceRepository defines operations for service management type ServiceRepository interface { Create(ctx context.Context, service *Service) error GetByID(ctx context.Context, id string) (*Service, error) GetByOrganization(ctx context.Context, organizationID string) ([]*Service, error) GetByType(ctx context.Context, serviceType ServiceType) ([]*Service, error) GetByDomain(ctx context.Context, domain string) ([]*Service, error) SearchByDescription(ctx context.Context, description string) ([]*Service, error) GetByServiceArea(ctx context.Context, lat, lng, radiusKm float64) ([]*Service, error) Update(ctx context.Context, service *Service) error Delete(ctx context.Context, id string) error GetAll(ctx context.Context) ([]*Service, error) // Discovery methods SearchWithLocation(ctx context.Context, query string, location *Point, radiusKm float64) ([]*Service, error) GetBySite(ctx context.Context, siteID string) ([]*Service, error) GetNearby(ctx context.Context, lat, lng, radiusKm float64) ([]*Service, error) } // Validate performs business rule validation func (s *Service) Validate() error { if s.Domain == "" { return fmt.Errorf("service domain cannot be empty") } if s.HourlyRate < 0 { return fmt.Errorf("hourly rate cannot be negative") } if s.ServiceAreaKm < 0 { return fmt.Errorf("service area cannot be negative") } return nil }