- 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
551 lines
14 KiB
Java
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
|
|
}
|
|
}
|