Initial commit
This commit is contained in:
380
docs/concepts/02-CLIENT.md
Normal file
380
docs/concepts/02-CLIENT.md
Normal file
@@ -0,0 +1,380 @@
|
||||
# 👤 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">
|
||||
````java
|
||||
@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">
|
||||
````java
|
||||
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**
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8080/api/v1/clients \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
**Réponse** (200 OK):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"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**
|
||||
|
||||
```bash
|
||||
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):
|
||||
```json
|
||||
{
|
||||
"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**
|
||||
|
||||
```bash
|
||||
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**
|
||||
|
||||
```bash
|
||||
# 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**
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8080/api/v1/clients/stats
|
||||
```
|
||||
|
||||
**Réponse**:
|
||||
```json
|
||||
{
|
||||
"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**:
|
||||
```bash
|
||||
cd btpxpress-server
|
||||
./mvnw test -Dtest=ClientServiceTest
|
||||
./mvnw test -Dtest=ClientResourceTest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Références
|
||||
|
||||
- [API Documentation complète](../API.md#clients)
|
||||
- [Schéma de base de données](../DATABASE.md#table-clients)
|
||||
- [Guide d'architecture](../architecture/domain-model.md#client)
|
||||
- [Service ClientService](../../src/main/java/dev/lions/btpxpress/application/service/ClientService.java)
|
||||
- [Resource ClientResource](../../src/main/java/dev/lions/btpxpress/adapter/http/ClientResource.java)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour**: 2025-09-30
|
||||
**Version**: 1.0
|
||||
**Auteur**: Documentation BTPXpress
|
||||
|
||||
Reference in New Issue
Block a user