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
This commit is contained in:
531
src/main/java/com/gbcm/server/impl/entity/Client.java
Normal file
531
src/main/java/com/gbcm/server/impl/entity/Client.java
Normal file
@@ -0,0 +1,531 @@
|
||||
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.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Entité représentant un client de la plateforme GBCM.
|
||||
* Un client est associé à un utilisateur et peut avoir plusieurs services.
|
||||
*
|
||||
* @author GBCM Development Team
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "clients", indexes = {
|
||||
@Index(name = "idx_clients_user_id", columnList = "user_id", unique = true),
|
||||
@Index(name = "idx_clients_company", columnList = "company_name"),
|
||||
@Index(name = "idx_clients_status", columnList = "status"),
|
||||
@Index(name = "idx_clients_deleted", columnList = "deleted")
|
||||
})
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "Client.findByUserId",
|
||||
query = "SELECT c FROM Client c WHERE c.user.id = :userId AND c.deleted = false"),
|
||||
@NamedQuery(name = "Client.findByStatus",
|
||||
query = "SELECT c FROM Client c WHERE c.status = :status AND c.deleted = false"),
|
||||
@NamedQuery(name = "Client.findByCompanyName",
|
||||
query = "SELECT c FROM Client c WHERE LOWER(c.companyName) LIKE LOWER(:companyName) AND c.deleted = false"),
|
||||
@NamedQuery(name = "Client.findActiveClients",
|
||||
query = "SELECT c FROM Client c WHERE c.status = 'ACTIVE' AND c.deleted = false")
|
||||
})
|
||||
public class Client extends BaseEntity {
|
||||
|
||||
/**
|
||||
* Identifiant unique du client.
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* Utilisateur associé à ce client.
|
||||
* Relation one-to-one obligatoire.
|
||||
*/
|
||||
@OneToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "user_id", nullable = false, unique = true,
|
||||
foreignKey = @ForeignKey(name = "fk_clients_user_id"))
|
||||
@NotNull(message = "L'utilisateur associé est obligatoire")
|
||||
private User user;
|
||||
|
||||
/**
|
||||
* Nom de l'entreprise du client.
|
||||
*/
|
||||
@Column(name = "company_name", nullable = false, length = 200)
|
||||
@NotBlank(message = "Le nom de l'entreprise est obligatoire")
|
||||
@Size(max = 200, message = "Le nom de l'entreprise ne peut pas dépasser 200 caractères")
|
||||
private String companyName;
|
||||
|
||||
/**
|
||||
* Secteur d'activité de l'entreprise.
|
||||
*/
|
||||
@Column(name = "industry", length = 100)
|
||||
@Size(max = 100, message = "Le secteur d'activité ne peut pas dépasser 100 caractères")
|
||||
private String industry;
|
||||
|
||||
/**
|
||||
* Taille de l'entreprise (nombre d'employés).
|
||||
*/
|
||||
@Column(name = "company_size")
|
||||
private Integer companySize;
|
||||
|
||||
/**
|
||||
* Chiffre d'affaires annuel de l'entreprise.
|
||||
*/
|
||||
@Column(name = "annual_revenue", precision = 15, scale = 2)
|
||||
private BigDecimal annualRevenue;
|
||||
|
||||
/**
|
||||
* Adresse de l'entreprise - ligne 1.
|
||||
*/
|
||||
@Column(name = "address_line1", length = 255)
|
||||
@Size(max = 255, message = "L'adresse ligne 1 ne peut pas dépasser 255 caractères")
|
||||
private String addressLine1;
|
||||
|
||||
/**
|
||||
* Adresse de l'entreprise - ligne 2.
|
||||
*/
|
||||
@Column(name = "address_line2", length = 255)
|
||||
@Size(max = 255, message = "L'adresse ligne 2 ne peut pas dépasser 255 caractères")
|
||||
private String addressLine2;
|
||||
|
||||
/**
|
||||
* Ville de l'entreprise.
|
||||
*/
|
||||
@Column(name = "city", length = 100)
|
||||
@Size(max = 100, message = "La ville ne peut pas dépasser 100 caractères")
|
||||
private String city;
|
||||
|
||||
/**
|
||||
* État/Province de l'entreprise.
|
||||
*/
|
||||
@Column(name = "state", length = 100)
|
||||
@Size(max = 100, message = "L'état ne peut pas dépasser 100 caractères")
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* Code postal de l'entreprise.
|
||||
*/
|
||||
@Column(name = "postal_code", length = 20)
|
||||
@Size(max = 20, message = "Le code postal ne peut pas dépasser 20 caractères")
|
||||
private String postalCode;
|
||||
|
||||
/**
|
||||
* Pays de l'entreprise.
|
||||
*/
|
||||
@Column(name = "country", length = 100)
|
||||
@Size(max = 100, message = "Le pays ne peut pas dépasser 100 caractères")
|
||||
private String country;
|
||||
|
||||
/**
|
||||
* Site web de l'entreprise.
|
||||
*/
|
||||
@Column(name = "website", length = 255)
|
||||
@Size(max = 255, message = "Le site web ne peut pas dépasser 255 caractères")
|
||||
private String website;
|
||||
|
||||
/**
|
||||
* Statut du client.
|
||||
*/
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
@NotNull(message = "Le statut est obligatoire")
|
||||
private ClientStatus status = ClientStatus.PROSPECT;
|
||||
|
||||
/**
|
||||
* Date de conversion de prospect à client.
|
||||
*/
|
||||
@Column(name = "converted_at")
|
||||
private LocalDateTime convertedAt;
|
||||
|
||||
/**
|
||||
* Type de service principal du client.
|
||||
*/
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "primary_service_type", length = 30)
|
||||
private ServiceType primaryServiceType;
|
||||
|
||||
/**
|
||||
* Valeur totale des contrats du client.
|
||||
*/
|
||||
@Column(name = "total_contract_value", precision = 15, scale = 2)
|
||||
private BigDecimal totalContractValue = BigDecimal.ZERO;
|
||||
|
||||
/**
|
||||
* Date de début de la relation client.
|
||||
*/
|
||||
@Column(name = "relationship_start_date")
|
||||
private LocalDate relationshipStartDate;
|
||||
|
||||
/**
|
||||
* Notes internes sur le client.
|
||||
*/
|
||||
@Column(name = "notes", columnDefinition = "TEXT")
|
||||
private String notes;
|
||||
|
||||
/**
|
||||
* Source d'acquisition du client.
|
||||
*/
|
||||
@Column(name = "acquisition_source", length = 100)
|
||||
@Size(max = 100, message = "La source d'acquisition ne peut pas dépasser 100 caractères")
|
||||
private String acquisitionSource;
|
||||
|
||||
/**
|
||||
* Constructeur par défaut.
|
||||
*/
|
||||
public Client() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructeur avec les champs obligatoires.
|
||||
*
|
||||
* @param user l'utilisateur associé
|
||||
* @param companyName le nom de l'entreprise
|
||||
*/
|
||||
public Client(User user, String companyName) {
|
||||
this();
|
||||
this.user = user;
|
||||
this.companyName = companyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit un prospect en client.
|
||||
*/
|
||||
public void convertToClient() {
|
||||
if (this.status == ClientStatus.PROSPECT) {
|
||||
this.status = ClientStatus.ACTIVE;
|
||||
this.convertedAt = LocalDateTime.now();
|
||||
this.relationshipStartDate = LocalDate.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Désactive le client.
|
||||
*/
|
||||
public void deactivate() {
|
||||
this.status = ClientStatus.INACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Réactive le client.
|
||||
*/
|
||||
public void reactivate() {
|
||||
this.status = ClientStatus.ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute une valeur au contrat total.
|
||||
*
|
||||
* @param amount le montant à ajouter
|
||||
*/
|
||||
public void addContractValue(BigDecimal amount) {
|
||||
if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.totalContractValue = this.totalContractValue.add(amount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'adresse complète formatée.
|
||||
*
|
||||
* @return l'adresse complète
|
||||
*/
|
||||
public String getFullAddress() {
|
||||
StringBuilder address = new StringBuilder();
|
||||
|
||||
if (addressLine1 != null && !addressLine1.trim().isEmpty()) {
|
||||
address.append(addressLine1);
|
||||
}
|
||||
|
||||
if (addressLine2 != null && !addressLine2.trim().isEmpty()) {
|
||||
if (address.length() > 0) address.append(", ");
|
||||
address.append(addressLine2);
|
||||
}
|
||||
|
||||
if (city != null && !city.trim().isEmpty()) {
|
||||
if (address.length() > 0) address.append(", ");
|
||||
address.append(city);
|
||||
}
|
||||
|
||||
if (state != null && !state.trim().isEmpty()) {
|
||||
if (address.length() > 0) address.append(", ");
|
||||
address.append(state);
|
||||
}
|
||||
|
||||
if (postalCode != null && !postalCode.trim().isEmpty()) {
|
||||
if (address.length() > 0) address.append(" ");
|
||||
address.append(postalCode);
|
||||
}
|
||||
|
||||
if (country != null && !country.trim().isEmpty()) {
|
||||
if (address.length() > 0) address.append(", ");
|
||||
address.append(country);
|
||||
}
|
||||
|
||||
return address.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le client est actif.
|
||||
*
|
||||
* @return true si le client est actif, false sinon
|
||||
*/
|
||||
public boolean isActiveClient() {
|
||||
return status == ClientStatus.ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le client est un prospect.
|
||||
*
|
||||
* @return true si c'est un prospect, false sinon
|
||||
*/
|
||||
public boolean isProspect() {
|
||||
return status == ClientStatus.PROSPECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode de recherche par ID utilisateur.
|
||||
*
|
||||
* @param userId l'ID de l'utilisateur
|
||||
* @return le client trouvé ou null
|
||||
*/
|
||||
public static Client findByUserId(Long userId) {
|
||||
return find("#Client.findByUserId", userId).firstResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode de recherche par statut.
|
||||
*
|
||||
* @param status le statut à rechercher
|
||||
* @return la liste des clients avec ce statut
|
||||
*/
|
||||
public static List<Client> findByStatus(ClientStatus status) {
|
||||
return find("#Client.findByStatus", status).list();
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode de recherche par nom d'entreprise.
|
||||
*
|
||||
* @param companyName le nom d'entreprise à rechercher
|
||||
* @return la liste des clients correspondants
|
||||
*/
|
||||
public static List<Client> findByCompanyName(String companyName) {
|
||||
String searchPattern = "%" + companyName + "%";
|
||||
return find("#Client.findByCompanyName", searchPattern).list();
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode de recherche des clients actifs.
|
||||
*
|
||||
* @return la liste des clients actifs
|
||||
*/
|
||||
public static List<Client> findActiveClients() {
|
||||
return find("#Client.findActiveClients").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 getCompanyName() {
|
||||
return companyName;
|
||||
}
|
||||
|
||||
public void setCompanyName(String companyName) {
|
||||
this.companyName = companyName;
|
||||
}
|
||||
|
||||
public String getIndustry() {
|
||||
return industry;
|
||||
}
|
||||
|
||||
public void setIndustry(String industry) {
|
||||
this.industry = industry;
|
||||
}
|
||||
|
||||
public Integer getCompanySize() {
|
||||
return companySize;
|
||||
}
|
||||
|
||||
public void setCompanySize(Integer companySize) {
|
||||
this.companySize = companySize;
|
||||
}
|
||||
|
||||
public BigDecimal getAnnualRevenue() {
|
||||
return annualRevenue;
|
||||
}
|
||||
|
||||
public void setAnnualRevenue(BigDecimal annualRevenue) {
|
||||
this.annualRevenue = annualRevenue;
|
||||
}
|
||||
|
||||
public String getAddressLine1() {
|
||||
return addressLine1;
|
||||
}
|
||||
|
||||
public void setAddressLine1(String addressLine1) {
|
||||
this.addressLine1 = addressLine1;
|
||||
}
|
||||
|
||||
public String getAddressLine2() {
|
||||
return addressLine2;
|
||||
}
|
||||
|
||||
public void setAddressLine2(String addressLine2) {
|
||||
this.addressLine2 = addressLine2;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getPostalCode() {
|
||||
return postalCode;
|
||||
}
|
||||
|
||||
public void setPostalCode(String postalCode) {
|
||||
this.postalCode = postalCode;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public String getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public void setWebsite(String website) {
|
||||
this.website = website;
|
||||
}
|
||||
|
||||
public ClientStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(ClientStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public LocalDateTime getConvertedAt() {
|
||||
return convertedAt;
|
||||
}
|
||||
|
||||
public void setConvertedAt(LocalDateTime convertedAt) {
|
||||
this.convertedAt = convertedAt;
|
||||
}
|
||||
|
||||
public ServiceType getPrimaryServiceType() {
|
||||
return primaryServiceType;
|
||||
}
|
||||
|
||||
public void setPrimaryServiceType(ServiceType primaryServiceType) {
|
||||
this.primaryServiceType = primaryServiceType;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalContractValue() {
|
||||
return totalContractValue;
|
||||
}
|
||||
|
||||
public void setTotalContractValue(BigDecimal totalContractValue) {
|
||||
this.totalContractValue = totalContractValue;
|
||||
}
|
||||
|
||||
public LocalDate getRelationshipStartDate() {
|
||||
return relationshipStartDate;
|
||||
}
|
||||
|
||||
public void setRelationshipStartDate(LocalDate relationshipStartDate) {
|
||||
this.relationshipStartDate = relationshipStartDate;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public String getAcquisitionSource() {
|
||||
return acquisitionSource;
|
||||
}
|
||||
|
||||
public void setAcquisitionSource(String acquisitionSource) {
|
||||
this.acquisitionSource = acquisitionSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Client{" +
|
||||
"id=" + id +
|
||||
", companyName='" + companyName + '\'' +
|
||||
", industry='" + industry + '\'' +
|
||||
", status=" + status +
|
||||
", totalContractValue=" + totalContractValue +
|
||||
", relationshipStartDate=" + relationshipStartDate +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Énumération des statuts de client.
|
||||
*/
|
||||
public enum ClientStatus {
|
||||
/**
|
||||
* Prospect - pas encore client.
|
||||
*/
|
||||
PROSPECT,
|
||||
|
||||
/**
|
||||
* Client actif.
|
||||
*/
|
||||
ACTIVE,
|
||||
|
||||
/**
|
||||
* Client inactif.
|
||||
*/
|
||||
INACTIVE,
|
||||
|
||||
/**
|
||||
* Ancien client.
|
||||
*/
|
||||
FORMER
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user