595 lines
15 KiB
Java
595 lines
15 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.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;
|
|
|
|
/**
|
|
* Devise du chiffre d'affaires.
|
|
*/
|
|
@Column(name = "revenue_currency", length = 3)
|
|
@Size(min = 3, max = 3, message = "Le code devise doit faire 3 caractères")
|
|
private String revenueCurrency = "USD";
|
|
|
|
/**
|
|
* Locale préférée.
|
|
*/
|
|
@Column(name = "preferred_locale", length = 20)
|
|
@Size(max = 20, message = "La locale ne peut pas dépasser 20 caractères")
|
|
private String preferredLocale = "fr-FR";
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* Date de début de service.
|
|
*/
|
|
@Column(name = "service_start_date")
|
|
private LocalDate serviceStartDate;
|
|
|
|
/**
|
|
* Date de fin de service.
|
|
*/
|
|
@Column(name = "service_end_date")
|
|
private LocalDate serviceEndDate;
|
|
|
|
/**
|
|
* 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 getRevenueCurrency() {
|
|
return revenueCurrency;
|
|
}
|
|
|
|
public void setRevenueCurrency(String revenueCurrency) {
|
|
this.revenueCurrency = revenueCurrency;
|
|
}
|
|
|
|
public String getPreferredLocale() {
|
|
return preferredLocale;
|
|
}
|
|
|
|
public void setPreferredLocale(String preferredLocale) {
|
|
this.preferredLocale = preferredLocale;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public LocalDate getServiceStartDate() {
|
|
return serviceStartDate;
|
|
}
|
|
|
|
public void setServiceStartDate(LocalDate serviceStartDate) {
|
|
this.serviceStartDate = serviceStartDate;
|
|
}
|
|
|
|
public LocalDate getServiceEndDate() {
|
|
return serviceEndDate;
|
|
}
|
|
|
|
public void setServiceEndDate(LocalDate serviceEndDate) {
|
|
this.serviceEndDate = serviceEndDate;
|
|
}
|
|
|
|
@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,
|
|
|
|
/**
|
|
* Client suspendu.
|
|
*/
|
|
SUSPENDED,
|
|
|
|
/**
|
|
* Ancien client.
|
|
*/
|
|
FORMER
|
|
}
|
|
}
|