package models import ( "time" "github.com/google/uuid" "gorm.io/gorm" ) // BaseEntity enthält gemeinsame Felder für alle Entitäten type BaseEntity struct { ID uuid.UUID `gorm:"type:uuid;primary_key"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } // BeforeCreate setzt eine neue UUID vor dem Erstellen func (base *BaseEntity) BeforeCreate(tx *gorm.DB) error { if base.ID == uuid.Nil { base.ID = uuid.New() } return nil } // TenantEntity erweitert BaseEntity um Company-ID für Multi-Tenancy type TenantEntity struct { BaseEntity CompanyID uuid.UUID `gorm:"type:uuid;index:idx_tenant"` } // Role repräsentiert eine Benutzerrolle type Role struct { BaseEntity Name string `gorm:"unique;not null"` Description string Permissions []Permission `gorm:"many2many:role_permissions;"` } // Permission repräsentiert eine einzelne Berechtigung type Permission struct { BaseEntity Resource string `gorm:"not null"` Action string `gorm:"not null"` UniqueID string `gorm:"uniqueIndex"` } // User repräsentiert einen Benutzer im System type User struct { TenantEntity Email string `gorm:"uniqueIndex;not null"` FirstName string LastName string PasswordHash string `gorm:"not null"` RoleID uuid.UUID `gorm:"type:uuid"` Role Role `gorm:"foreignKey:RoleID"` HourlyRate float64 IsActive bool `gorm:"default:true"` } // FullName gibt den vollständigen Namen des Benutzers zurück func (u User) FullName() string { return u.FirstName + " " + u.LastName } // TimeEntry repräsentiert eine Zeitbuchung type TimeEntry struct { TenantEntity UserID uuid.UUID `gorm:"type:uuid;index:idx_user"` User User `gorm:"foreignKey:UserID"` ProjectID uuid.UUID `gorm:"type:uuid;index:idx_project"` Project Project `gorm:"foreignKey:ProjectID"` ActivityID uuid.UUID `gorm:"type:uuid"` Activity Activity `gorm:"foreignKey:ActivityID"` TaskID *uuid.UUID `gorm:"type:uuid;null"` Task *Task `gorm:"foreignKey:TaskID"` StartTime time.Time `gorm:"not null;index:idx_time_range"` EndTime time.Time `gorm:"not null;index:idx_time_range"` DurationMinutes int `gorm:"not null"` Description string BillablePercentage int `gorm:"default:100"` BillingRate float64 } type Project struct { TenantEntity Name string } type Activity struct { TenantEntity Name string } type Task struct { TenantEntity Name string } // CalculateBillableAmount berechnet den abrechenbaren Betrag func (t TimeEntry) CalculateBillableAmount() float64 { hours := float64(t.DurationMinutes) / 60.0 return hours * t.BillingRate * (float64(t.BillablePercentage) / 100.0) }