Files
gbcm-server-impl-quarkus/src/main/java/com/gbcm/server/impl/entity/Coach.java
dahoud 9d8ce834e8 Task 1.2 - Entités JPA fondamentales
- Création de BaseEntity avec audit trail et soft delete
- Création de l'entité User avec Quarkus Security JPA
- Création de l'entité Client avec informations d'entreprise
- Création de l'entité Coach avec informations professionnelles
- Relations JPA one-to-one entre User-Client et User-Coach
- Migrations Flyway V1, V2, V3 pour les tables
- Données de test dans import.sql
- Compilation réussie du module d'implémentation
2025-10-06 20:11:18 +00:00

551 lines
14 KiB
Java

package com.gbcm.server.impl.entity;
import com.gbcm.server.api.enums.ServiceType;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.Set;
/**
* Entité représentant un coach de la plateforme GBCM.
* Un coach est associé à un utilisateur et peut offrir différents services.
*
* @author GBCM Development Team
* @version 1.0
* @since 1.0
*/
@Entity
@Table(name = "coaches", indexes = {
@Index(name = "idx_coaches_user_id", columnList = "user_id", unique = true),
@Index(name = "idx_coaches_status", columnList = "status"),
@Index(name = "idx_coaches_specialization", columnList = "specialization"),
@Index(name = "idx_coaches_deleted", columnList = "deleted")
})
@NamedQueries({
@NamedQuery(name = "Coach.findByUserId",
query = "SELECT c FROM Coach c WHERE c.user.id = :userId AND c.deleted = false"),
@NamedQuery(name = "Coach.findByStatus",
query = "SELECT c FROM Coach c WHERE c.status = :status AND c.deleted = false"),
@NamedQuery(name = "Coach.findBySpecialization",
query = "SELECT c FROM Coach c WHERE c.specialization = :specialization AND c.deleted = false"),
@NamedQuery(name = "Coach.findAvailableCoaches",
query = "SELECT c FROM Coach c WHERE c.status = 'ACTIVE' AND c.availableForBooking = true AND c.deleted = false")
})
public class Coach extends BaseEntity {
/**
* Identifiant unique du coach.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* Utilisateur associé à ce coach.
* Relation one-to-one obligatoire.
*/
@OneToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", nullable = false, unique = true,
foreignKey = @ForeignKey(name = "fk_coaches_user_id"))
@NotNull(message = "L'utilisateur associé est obligatoire")
private User user;
/**
* Spécialisation principale du coach.
*/
@Column(name = "specialization", nullable = false, length = 100)
@NotBlank(message = "La spécialisation est obligatoire")
@Size(max = 100, message = "La spécialisation ne peut pas dépasser 100 caractères")
private String specialization;
/**
* Biographie professionnelle du coach.
*/
@Column(name = "bio", columnDefinition = "TEXT")
private String bio;
/**
* Années d'expérience du coach.
*/
@Column(name = "years_of_experience")
private Integer yearsOfExperience;
/**
* Certifications du coach.
*/
@Column(name = "certifications", columnDefinition = "TEXT")
private String certifications;
/**
* Langues parlées par le coach.
*/
@Column(name = "languages", length = 255)
@Size(max = 255, message = "Les langues ne peuvent pas dépasser 255 caractères")
private String languages;
/**
* Tarif horaire du coach pour les sessions individuelles.
*/
@Column(name = "hourly_rate", precision = 10, scale = 2)
private BigDecimal hourlyRate;
/**
* Statut du coach.
*/
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 20)
@NotNull(message = "Le statut est obligatoire")
private CoachStatus status = CoachStatus.ACTIVE;
/**
* Disponibilité pour les réservations.
*/
@Column(name = "available_for_booking", nullable = false)
private boolean availableForBooking = true;
/**
* Types de services offerts par le coach.
*/
@ElementCollection(targetClass = ServiceType.class)
@CollectionTable(name = "coach_service_types",
joinColumns = @JoinColumn(name = "coach_id"),
foreignKey = @ForeignKey(name = "fk_coach_service_types_coach_id"))
@Column(name = "service_type", length = 30)
@Enumerated(EnumType.STRING)
private Set<ServiceType> serviceTypes;
/**
* Heures de travail - début.
*/
@Column(name = "working_hours_start")
private LocalTime workingHoursStart;
/**
* Heures de travail - fin.
*/
@Column(name = "working_hours_end")
private LocalTime workingHoursEnd;
/**
* Jours de travail (format: MONDAY,TUESDAY,WEDNESDAY...).
*/
@Column(name = "working_days", length = 100)
@Size(max = 100, message = "Les jours de travail ne peuvent pas dépasser 100 caractères")
private String workingDays;
/**
* Fuseau horaire du coach.
*/
@Column(name = "timezone", length = 50)
@Size(max = 50, message = "Le fuseau horaire ne peut pas dépasser 50 caractères")
private String timezone;
/**
* Date de début d'activité comme coach.
*/
@Column(name = "start_date")
private LocalDate startDate;
/**
* Date de fin d'activité comme coach.
*/
@Column(name = "end_date")
private LocalDate endDate;
/**
* Note moyenne du coach (calculée à partir des évaluations).
*/
@Column(name = "average_rating", precision = 3, scale = 2)
private BigDecimal averageRating;
/**
* Nombre total d'évaluations reçues.
*/
@Column(name = "total_ratings", nullable = false)
private int totalRatings = 0;
/**
* Nombre total de sessions effectuées.
*/
@Column(name = "total_sessions", nullable = false)
private int totalSessions = 0;
/**
* Revenus totaux générés.
*/
@Column(name = "total_revenue", precision = 15, scale = 2)
private BigDecimal totalRevenue = BigDecimal.ZERO;
/**
* Notes internes sur le coach.
*/
@Column(name = "notes", columnDefinition = "TEXT")
private String notes;
/**
* Constructeur par défaut.
*/
public Coach() {
super();
}
/**
* Constructeur avec les champs obligatoires.
*
* @param user l'utilisateur associé
* @param specialization la spécialisation du coach
*/
public Coach(User user, String specialization) {
this();
this.user = user;
this.specialization = specialization;
this.startDate = LocalDate.now();
}
/**
* Active le coach.
*/
public void activate() {
this.status = CoachStatus.ACTIVE;
this.availableForBooking = true;
}
/**
* Désactive le coach.
*/
public void deactivate() {
this.status = CoachStatus.INACTIVE;
this.availableForBooking = false;
}
/**
* Met le coach en congé.
*/
public void setOnLeave() {
this.status = CoachStatus.ON_LEAVE;
this.availableForBooking = false;
}
/**
* Termine l'activité du coach.
*/
public void terminate() {
this.status = CoachStatus.TERMINATED;
this.availableForBooking = false;
this.endDate = LocalDate.now();
}
/**
* Met à jour la note moyenne après une nouvelle évaluation.
*
* @param newRating la nouvelle note reçue
*/
public void updateRating(BigDecimal newRating) {
if (newRating != null && newRating.compareTo(BigDecimal.ZERO) > 0) {
if (averageRating == null) {
averageRating = newRating;
totalRatings = 1;
} else {
BigDecimal totalScore = averageRating.multiply(new BigDecimal(totalRatings));
totalScore = totalScore.add(newRating);
totalRatings++;
averageRating = totalScore.divide(new BigDecimal(totalRatings), 2, java.math.RoundingMode.HALF_UP);
}
}
}
/**
* Incrémente le nombre de sessions effectuées.
*/
public void incrementSessionCount() {
this.totalSessions++;
}
/**
* Ajoute des revenus au total.
*
* @param amount le montant à ajouter
*/
public void addRevenue(BigDecimal amount) {
if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) {
this.totalRevenue = this.totalRevenue.add(amount);
}
}
/**
* Vérifie si le coach est disponible pour les réservations.
*
* @return true si disponible, false sinon
*/
public boolean isAvailableForBooking() {
return availableForBooking && status == CoachStatus.ACTIVE;
}
/**
* Vérifie si le coach offre un type de service spécifique.
*
* @param serviceType le type de service à vérifier
* @return true si le coach offre ce service, false sinon
*/
public boolean offersService(ServiceType serviceType) {
return serviceTypes != null && serviceTypes.contains(serviceType);
}
/**
* Méthode de recherche par ID utilisateur.
*
* @param userId l'ID de l'utilisateur
* @return le coach trouvé ou null
*/
public static Coach findByUserId(Long userId) {
return find("#Coach.findByUserId", userId).firstResult();
}
/**
* Méthode de recherche par statut.
*
* @param status le statut à rechercher
* @return la liste des coaches avec ce statut
*/
public static List<Coach> findByStatus(CoachStatus status) {
return find("#Coach.findByStatus", status).list();
}
/**
* Méthode de recherche par spécialisation.
*
* @param specialization la spécialisation à rechercher
* @return la liste des coaches avec cette spécialisation
*/
public static List<Coach> findBySpecialization(String specialization) {
return find("#Coach.findBySpecialization", specialization).list();
}
/**
* Méthode de recherche des coaches disponibles.
*
* @return la liste des coaches disponibles pour réservation
*/
public static List<Coach> findAvailableCoaches() {
return find("#Coach.findAvailableCoaches").list();
}
// Getters et Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getSpecialization() {
return specialization;
}
public void setSpecialization(String specialization) {
this.specialization = specialization;
}
public String getBio() {
return bio;
}
public void setBio(String bio) {
this.bio = bio;
}
public Integer getYearsOfExperience() {
return yearsOfExperience;
}
public void setYearsOfExperience(Integer yearsOfExperience) {
this.yearsOfExperience = yearsOfExperience;
}
public String getCertifications() {
return certifications;
}
public void setCertifications(String certifications) {
this.certifications = certifications;
}
public String getLanguages() {
return languages;
}
public void setLanguages(String languages) {
this.languages = languages;
}
public BigDecimal getHourlyRate() {
return hourlyRate;
}
public void setHourlyRate(BigDecimal hourlyRate) {
this.hourlyRate = hourlyRate;
}
public CoachStatus getStatus() {
return status;
}
public void setStatus(CoachStatus status) {
this.status = status;
}
public void setAvailableForBooking(boolean availableForBooking) {
this.availableForBooking = availableForBooking;
}
public Set<ServiceType> getServiceTypes() {
return serviceTypes;
}
public void setServiceTypes(Set<ServiceType> serviceTypes) {
this.serviceTypes = serviceTypes;
}
public LocalTime getWorkingHoursStart() {
return workingHoursStart;
}
public void setWorkingHoursStart(LocalTime workingHoursStart) {
this.workingHoursStart = workingHoursStart;
}
public LocalTime getWorkingHoursEnd() {
return workingHoursEnd;
}
public void setWorkingHoursEnd(LocalTime workingHoursEnd) {
this.workingHoursEnd = workingHoursEnd;
}
public String getWorkingDays() {
return workingDays;
}
public void setWorkingDays(String workingDays) {
this.workingDays = workingDays;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
public BigDecimal getAverageRating() {
return averageRating;
}
public void setAverageRating(BigDecimal averageRating) {
this.averageRating = averageRating;
}
public int getTotalRatings() {
return totalRatings;
}
public void setTotalRatings(int totalRatings) {
this.totalRatings = totalRatings;
}
public int getTotalSessions() {
return totalSessions;
}
public void setTotalSessions(int totalSessions) {
this.totalSessions = totalSessions;
}
public BigDecimal getTotalRevenue() {
return totalRevenue;
}
public void setTotalRevenue(BigDecimal totalRevenue) {
this.totalRevenue = totalRevenue;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
@Override
public String toString() {
return "Coach{" +
"id=" + id +
", specialization='" + specialization + '\'' +
", status=" + status +
", availableForBooking=" + availableForBooking +
", averageRating=" + averageRating +
", totalSessions=" + totalSessions +
", totalRevenue=" + totalRevenue +
'}';
}
/**
* Énumération des statuts de coach.
*/
public enum CoachStatus {
/**
* Coach actif et disponible.
*/
ACTIVE,
/**
* Coach inactif temporairement.
*/
INACTIVE,
/**
* Coach en congé.
*/
ON_LEAVE,
/**
* Coach dont le contrat est terminé.
*/
TERMINATED
}
}