Initial commit
This commit is contained in:
278
docs/concepts/09-DEVIS.md
Normal file
278
docs/concepts/09-DEVIS.md
Normal file
@@ -0,0 +1,278 @@
|
||||
# 💰 CONCEPT: DEVIS
|
||||
|
||||
## 📌 Vue d'ensemble
|
||||
|
||||
Le concept **DEVIS** gère les devis et la facturation des chantiers. Il inclut les lignes de devis, calculs automatiques, et génération PDF.
|
||||
|
||||
**Importance**: ⭐⭐⭐⭐ (Concept stratégique)
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Fichiers concernés
|
||||
|
||||
### **Entités JPA**
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| `Devis.java` | Entité principale devis |
|
||||
| `LigneDevis.java` | Ligne de devis |
|
||||
| `StatutDevis.java` | Enum (BROUILLON, ENVOYE, ACCEPTE, REFUSE, EXPIRE) |
|
||||
| `Facture.java` | Entité facture |
|
||||
| `LigneFacture.java` | Ligne de facture |
|
||||
|
||||
### **Services**
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| `DevisService.java` | Service métier devis |
|
||||
| `FactureService.java` | Service métier factures |
|
||||
| `PdfGeneratorService.java` | Génération PDF |
|
||||
|
||||
### **Resources**
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| `DevisResource.java` | API REST devis |
|
||||
| `FactureResource.java` | API REST factures |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Modèle de données
|
||||
|
||||
### **Entité Devis**
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "devis")
|
||||
public class Devis extends PanacheEntityBase {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
private UUID id;
|
||||
|
||||
@Column(name = "numero", unique = true, nullable = false)
|
||||
private String numero;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "client_id", nullable = false)
|
||||
private Client client;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "chantier_id")
|
||||
private Chantier chantier;
|
||||
|
||||
@Column(name = "date_emission", nullable = false)
|
||||
private LocalDate dateEmission;
|
||||
|
||||
@Column(name = "date_validite")
|
||||
private LocalDate dateValidite;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "statut", nullable = false)
|
||||
private StatutDevis statut = StatutDevis.BROUILLON;
|
||||
|
||||
@OneToMany(mappedBy = "devis", cascade = CascadeType.ALL)
|
||||
private List<LigneDevis> lignes;
|
||||
|
||||
@Column(name = "montant_ht", precision = 10, scale = 2)
|
||||
private BigDecimal montantHT = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "montant_tva", precision = 10, scale = 2)
|
||||
private BigDecimal montantTVA = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "montant_ttc", precision = 10, scale = 2)
|
||||
private BigDecimal montantTTC = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "taux_tva", precision = 5, scale = 2)
|
||||
private BigDecimal tauxTVA = new BigDecimal("20.00");
|
||||
}
|
||||
```
|
||||
|
||||
### **Enum StatutDevis**
|
||||
|
||||
```java
|
||||
public enum StatutDevis {
|
||||
BROUILLON, // En cours de rédaction
|
||||
ENVOYE, // Envoyé au client
|
||||
ACCEPTE, // Accepté par le client
|
||||
REFUSE, // Refusé par le client
|
||||
EXPIRE // Expiré (date de validité dépassée)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 API REST
|
||||
|
||||
### **Endpoints Devis**
|
||||
|
||||
| Méthode | Endpoint | Description |
|
||||
|---------|----------|-------------|
|
||||
| GET | `/api/v1/devis` | Liste devis |
|
||||
| GET | `/api/v1/devis/{id}` | Détails |
|
||||
| POST | `/api/v1/devis` | Créer |
|
||||
| PUT | `/api/v1/devis/{id}` | Modifier |
|
||||
| PUT | `/api/v1/devis/{id}/envoyer` | Envoyer au client |
|
||||
| PUT | `/api/v1/devis/{id}/accepter` | Accepter |
|
||||
| PUT | `/api/v1/devis/{id}/refuser` | Refuser |
|
||||
| GET | `/api/v1/devis/{id}/pdf` | Générer PDF |
|
||||
| GET | `/api/v1/devis/stats` | Statistiques |
|
||||
|
||||
### **Endpoints Factures**
|
||||
|
||||
| Méthode | Endpoint | Description |
|
||||
|---------|----------|-------------|
|
||||
| GET | `/api/v1/factures` | Liste factures |
|
||||
| GET | `/api/v1/factures/{id}` | Détails |
|
||||
| POST | `/api/v1/factures` | Créer |
|
||||
| POST | `/api/v1/factures/depuis-devis/{devisId}` | Créer depuis devis |
|
||||
| GET | `/api/v1/factures/{id}/pdf` | Générer PDF |
|
||||
|
||||
---
|
||||
|
||||
## 💻 Exemples
|
||||
|
||||
### **Créer un devis**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/devis \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"clientId": "client-uuid",
|
||||
"chantierId": "chantier-uuid",
|
||||
"dateEmission": "2025-10-01",
|
||||
"dateValidite": "2025-11-01",
|
||||
"tauxTVA": 20.00,
|
||||
"lignes": [
|
||||
{
|
||||
"designation": "Terrassement et fondations",
|
||||
"quantite": 1,
|
||||
"unite": "FORFAIT",
|
||||
"prixUnitaireHT": 5000.00
|
||||
},
|
||||
{
|
||||
"designation": "Maçonnerie murs porteurs",
|
||||
"quantite": 45,
|
||||
"unite": "METRE_CARRE",
|
||||
"prixUnitaireHT": 120.00
|
||||
},
|
||||
{
|
||||
"designation": "Charpente traditionnelle",
|
||||
"quantite": 1,
|
||||
"unite": "FORFAIT",
|
||||
"prixUnitaireHT": 8000.00
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
**Réponse**:
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"numero": "DEV-2025-001",
|
||||
"client": "Jean Dupont",
|
||||
"chantier": "Construction Villa Moderne",
|
||||
"dateEmission": "2025-10-01",
|
||||
"dateValidite": "2025-11-01",
|
||||
"statut": "BROUILLON",
|
||||
"lignes": [
|
||||
{
|
||||
"designation": "Terrassement et fondations",
|
||||
"quantite": 1,
|
||||
"prixUnitaireHT": 5000.00,
|
||||
"montantHT": 5000.00
|
||||
},
|
||||
{
|
||||
"designation": "Maçonnerie murs porteurs",
|
||||
"quantite": 45,
|
||||
"prixUnitaireHT": 120.00,
|
||||
"montantHT": 5400.00
|
||||
},
|
||||
{
|
||||
"designation": "Charpente traditionnelle",
|
||||
"quantite": 1,
|
||||
"prixUnitaireHT": 8000.00,
|
||||
"montantHT": 8000.00
|
||||
}
|
||||
],
|
||||
"montantHT": 18400.00,
|
||||
"montantTVA": 3680.00,
|
||||
"montantTTC": 22080.00
|
||||
}
|
||||
```
|
||||
|
||||
### **Envoyer un devis**
|
||||
|
||||
```bash
|
||||
curl -X PUT http://localhost:8080/api/v1/devis/{id}/envoyer \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"emailClient": "jean.dupont@example.com",
|
||||
"message": "Veuillez trouver ci-joint notre devis"
|
||||
}'
|
||||
```
|
||||
|
||||
### **Générer PDF**
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8080/api/v1/devis/{id}/pdf \
|
||||
-H "Accept: application/pdf" \
|
||||
--output devis.pdf
|
||||
```
|
||||
|
||||
### **Créer facture depuis devis**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/factures/depuis-devis/{devisId}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Services métier
|
||||
|
||||
### **DevisService**
|
||||
|
||||
**Méthodes principales**:
|
||||
- `create(DevisDTO)` - Créer devis
|
||||
- `calculerMontants(UUID id)` - Calculer HT/TVA/TTC
|
||||
- `envoyer(UUID id)` - Envoyer au client
|
||||
- `accepter(UUID id)` - Accepter
|
||||
- `refuser(UUID id)` - Refuser
|
||||
- `genererPDF(UUID id)` - Générer PDF
|
||||
|
||||
### **FactureService**
|
||||
|
||||
**Méthodes principales**:
|
||||
- `create(FactureDTO)` - Créer facture
|
||||
- `creerDepuisDevis(UUID devisId)` - Créer depuis devis
|
||||
- `genererPDF(UUID id)` - Générer PDF
|
||||
|
||||
---
|
||||
|
||||
## 📈 Relations
|
||||
|
||||
- **CLIENT** ⬅️ Un devis est adressé à un client
|
||||
- **CHANTIER** ⬅️ Un devis peut être lié à un chantier
|
||||
- **FACTURE** ➡️ Un devis accepté génère une facture
|
||||
|
||||
---
|
||||
|
||||
## ✅ Validations
|
||||
|
||||
- ✅ Numéro unique
|
||||
- ✅ Client obligatoire
|
||||
- ✅ Au moins une ligne
|
||||
- ✅ Montants positifs
|
||||
- ✅ Date validité > date émission
|
||||
- ✅ Taux TVA entre 0 et 100
|
||||
|
||||
---
|
||||
|
||||
## 📚 Références
|
||||
|
||||
- [Concept CLIENT](./02-CLIENT.md)
|
||||
- [Concept CHANTIER](./01-CHANTIER.md)
|
||||
- [Concept BUDGET](./10-BUDGET.md)
|
||||
|
||||
---
|
||||
|
||||
**Dernière mise à jour**: 2025-09-30
|
||||
**Version**: 1.0
|
||||
|
||||
Reference in New Issue
Block a user