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

6.5 KiB

💰 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

@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

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

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:

{
  "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

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

curl -X GET http://localhost:8080/api/v1/devis/{id}/pdf \
  -H "Accept: application/pdf" \
  --output devis.pdf

Créer facture depuis devis

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


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