11 KiB
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
- API Documentation complète
- Schéma de base de données
- Guide d'architecture
- Service ClientService
- Resource ClientResource
Dernière mise à jour: 2025-09-30
Version: 1.0
Auteur: Documentation BTPXpress