Files
btpxpress-backend/docs/concepts/02-CLIENT.md
2025-10-01 01:37:34 +00:00

11 KiB

👤 CONCEPT: CLIENT

📌 Vue d'ensemble

Le concept CLIENT représente les clients de l'entreprise BTP, qu'ils soient particuliers ou professionnels. Il gère toutes les informations de contact, coordonnées, et relations avec les chantiers et devis.

Importance: (Concept fondamental)


🗂️ Fichiers concernés

Entités JPA (domain/core/entity/)

Fichier Description Lignes
Client.java Entité principale représentant un client 113
TypeClient.java Enum des types de clients (PARTICULIER, PROFESSIONNEL) 21

DTOs (domain/shared/dto/)

Fichier Description
ClientCreateDTO.java DTO pour créer/modifier un client

Services (application/service/)

Fichier Description
ClientService.java Service métier pour la gestion des clients

Resources (API REST) (adapter/http/)

Fichier Description
ClientResource.java Endpoints REST pour les clients

📊 Modèle de données

Entité Client

<augment_code_snippet path="btpxpress-server/src/main/java/dev/lions/btpxpress/domain/core/entity/Client.java" mode="EXCERPT">

@Entity
@Table(name = "clients")
@Data
@Builder
public class Client extends PanacheEntityBase {
  
  @Id
  @GeneratedValue(strategy = GenerationType.UUID)
  private UUID id;
  
  @NotBlank(message = "Le nom est obligatoire")
  @Column(name = "nom", nullable = false, length = 100)
  private String nom;
  
  @NotBlank(message = "Le prénom est obligatoire")
  @Column(name = "prenom", nullable = false, length = 100)
  private String prenom;
  
  @Column(name = "entreprise", length = 200)
  private String entreprise;
  
  @Email(message = "Email invalide")
  @Column(name = "email", unique = true, length = 255)
  private String email;
  
  @Pattern(regexp = "^(?:(?:\\+|00)33|0)\\s*[1-9](?:[\\s.-]*\\d{2}){4}$")
  @Column(name = "telephone", length = 20)
  private String telephone;
  
  @Enumerated(EnumType.STRING)
  @Column(name = "type_client", length = 20)
  private TypeClient type = TypeClient.PARTICULIER;
  
  // Relations
  @OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
  private List<Chantier> chantiers;
  
  @OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
  private List<Devis> devis;
}

</augment_code_snippet>

Enum TypeClient

<augment_code_snippet path="btpxpress-server/src/main/java/dev/lions/btpxpress/domain/core/entity/TypeClient.java" mode="EXCERPT">

public enum TypeClient {
  PARTICULIER("Particulier"),
  PROFESSIONNEL("Professionnel");

  private final String label;
  
  TypeClient(String label) {
    this.label = label;
  }
  
  public String getLabel() {
    return label;
  }
}

</augment_code_snippet>

Champs principaux

Champ Type Obligatoire Description
id UUID Oui Identifiant unique
nom String(100) Oui Nom du client
prenom String(100) Oui Prénom du client
entreprise String(200) Non Nom de l'entreprise (si professionnel)
email String(255) Non Email (unique)
telephone String(20) Non Téléphone (format français validé)
adresse String(500) Non Adresse postale
codePostal String(10) Non Code postal
ville String(100) Non Ville
numeroTVA String(20) Non Numéro de TVA intracommunautaire
siret String(14) Non Numéro SIRET (entreprises françaises)
type TypeClient Oui Type de client (défaut: PARTICULIER)
actif Boolean Oui Client actif (défaut: true)
dateCreation LocalDateTime Auto Date de création
dateModification LocalDateTime Auto Date de modification

Relations

Relation Type Entité cible Description
chantiers OneToMany Chantier Liste des chantiers du client
devis OneToMany Devis Liste des devis du client

🔌 API REST

Base URL: /api/v1/clients

Endpoints disponibles

Méthode Endpoint Description Permission
GET /api/v1/clients Liste tous les clients CLIENTS_READ
GET /api/v1/clients/{id} Détails d'un client CLIENTS_READ
POST /api/v1/clients Créer un client CLIENTS_CREATE
PUT /api/v1/clients/{id} Modifier un client CLIENTS_UPDATE
DELETE /api/v1/clients/{id} Supprimer un client CLIENTS_DELETE
GET /api/v1/clients/search Rechercher des clients CLIENTS_READ
GET /api/v1/clients/stats Statistiques clients CLIENTS_READ

Paramètres de requête (Query Params)

Paramètre Type Description Exemple
page Integer Numéro de page (0-based) ?page=0
size Integer Taille de la page ?size=20
search String Terme de recherche ?search=dupont

💻 Exemples d'utilisation

1. Récupérer tous les clients

curl -X GET http://localhost:8080/api/v1/clients \
  -H "Accept: application/json"

Réponse (200 OK):

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "nom": "Dupont",
    "prenom": "Jean",
    "email": "jean.dupont@example.com",
    "telephone": "+33 6 12 34 56 78",
    "adresse": "123 Rue de la Paix",
    "codePostal": "75002",
    "ville": "Paris",
    "type": "PARTICULIER",
    "actif": true,
    "dateCreation": "2025-01-15T10:30:00"
  },
  {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "nom": "Martin",
    "prenom": "Sophie",
    "entreprise": "BTP Solutions SARL",
    "email": "contact@btpsolutions.fr",
    "telephone": "+33 1 23 45 67 89",
    "siret": "12345678901234",
    "numeroTVA": "FR12345678901",
    "type": "PROFESSIONNEL",
    "actif": true
  }
]

2. Créer un nouveau client particulier

curl -X POST http://localhost:8080/api/v1/clients \
  -H "Content-Type: application/json" \
  -d '{
    "nom": "Durand",
    "prenom": "Pierre",
    "email": "pierre.durand@example.com",
    "telephone": "+33 6 98 76 54 32",
    "adresse": "45 Avenue des Champs",
    "codePostal": "75008",
    "ville": "Paris",
    "type": "PARTICULIER"
  }'

Réponse (201 Created):

{
  "id": "generated-uuid",
  "nom": "Durand",
  "prenom": "Pierre",
  "email": "pierre.durand@example.com",
  "type": "PARTICULIER",
  "actif": true,
  "dateCreation": "2025-09-30T14:25:00"
}

3. Créer un client professionnel

curl -X POST http://localhost:8080/api/v1/clients \
  -H "Content-Type: application/json" \
  -d '{
    "nom": "Entreprise",
    "prenom": "Construction",
    "entreprise": "ABC Construction SA",
    "email": "contact@abc-construction.fr",
    "telephone": "+33 1 45 67 89 01",
    "adresse": "10 Boulevard Haussmann",
    "codePostal": "75009",
    "ville": "Paris",
    "siret": "98765432109876",
    "numeroTVA": "FR98765432109",
    "type": "PROFESSIONNEL"
  }'

4. Rechercher des clients

# Par nom
curl -X GET "http://localhost:8080/api/v1/clients/search?search=dupont"

# Avec pagination
curl -X GET "http://localhost:8080/api/v1/clients?page=0&size=10"

5. Obtenir les statistiques

curl -X GET http://localhost:8080/api/v1/clients/stats

Réponse:

{
  "totalClients": 156,
  "clientsActifs": 142,
  "particuliers": 98,
  "professionnels": 58,
  "nouveauxCeMois": 12,
  "avecChantiers": 87,
  "sansChantiers": 69
}

🔧 Services métier

ClientService

Méthodes principales:

Méthode Description Retour
findAll() Récupère tous les clients List<Client>
findAll(int page, int size) Récupère avec pagination List<Client>
findById(UUID id) Récupère par ID Optional<Client>
findByIdRequired(UUID id) Récupère par ID (exception si absent) Client
create(ClientCreateDTO dto) Crée un client Client
update(UUID id, ClientCreateDTO dto) Met à jour Client
delete(UUID id) Supprime (soft delete) void
search(String term) Recherche textuelle List<Client>
findByType(TypeClient type) Filtre par type List<Client>
findActifs() Clients actifs uniquement List<Client>
getStatistics() Statistiques globales Object

🔐 Permissions requises

Permission Description Rôles autorisés
CLIENTS_READ Lecture des clients ADMIN, MANAGER, CHEF_CHANTIER, COMPTABLE
CLIENTS_CREATE Création de clients ADMIN, MANAGER
CLIENTS_UPDATE Modification de clients ADMIN, MANAGER
CLIENTS_DELETE Suppression de clients ADMIN, MANAGER
CLIENTS_ASSIGN Assignation à des chantiers ADMIN, MANAGER

📈 Relations avec autres concepts

Dépendances directes:

  • CHANTIER ➡️ Un client peut avoir plusieurs chantiers
  • DEVIS ➡️ Un client peut avoir plusieurs devis
  • FACTURE ➡️ Un client peut avoir plusieurs factures (via chantiers)

Utilisé par:

  • CHANTIER - Chaque chantier appartient à un client
  • DEVIS - Chaque devis est lié à un client
  • FACTURE - Chaque facture est adressée à un client

Validations

Validations automatiques:

  • Nom : Obligatoire, max 100 caractères
  • Prénom : Obligatoire, max 100 caractères
  • Email : Format email valide, unique
  • Téléphone : Format français valide (regex)
  • SIRET : 14 caractères (si renseigné)
  • Type : PARTICULIER ou PROFESSIONNEL

Règles métier:

  • Un client professionnel devrait avoir un SIRET et/ou numéro TVA
  • Un client particulier n'a généralement pas d'entreprise
  • L'email doit être unique dans le système
  • Le téléphone doit respecter le format français

🧪 Tests

Tests unitaires

  • Fichier: ClientServiceTest.java
  • Couverture: Logique métier, validations, recherche

Tests d'intégration

  • Fichier: ClientResourceTest.java
  • Couverture: Endpoints REST, sérialisation JSON

Commande pour exécuter les tests:

cd btpxpress-server
./mvnw test -Dtest=ClientServiceTest
./mvnw test -Dtest=ClientResourceTest

📚 Références


Dernière mise à jour: 2025-09-30
Version: 1.0
Auteur: Documentation BTPXpress