diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/Licence.java b/as-talange-core/src/main/java/com/astalange/core/entity/Licence.java index 1e585bc..6d4b2e2 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/Licence.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/Licence.java @@ -50,15 +50,21 @@ public class Licence { @Column(name = "sport_easy_email_sent_at") private java.time.LocalDateTime sportEasyEmailSentAt; + @Column(name = "reduction_educateur", nullable = false) + private Boolean reductionEducateur = false; + + @Column(name = "pourcentage_reduction_educateur") + private Integer pourcentageReductionEducateur = 100; + @OneToMany(mappedBy = "licence", cascade = CascadeType.ALL, orphanRemoval = true) private List paiements = new ArrayList<>(); @OneToMany(mappedBy = "licence", cascade = CascadeType.ALL, orphanRemoval = true) private List dotations = new ArrayList<>(); - // Logic for Global Total Price + // Logic for Raw Price (before reduction) @Transient - public BigDecimal getPrixTotal() { + public BigDecimal getPrixBrut() { if (categorie == null) return BigDecimal.ZERO; BigDecimal prixTotal = (adherent != null && adherent.isResidentTalange()) @@ -69,7 +75,7 @@ public class Licence { if (dotations != null) { for (Dotation dot : dotations) { - if (dot.getChoisi() && dot.getEquipement() != null) { + if (dot != null && Boolean.TRUE.equals(dot.getChoisi()) && dot.getEquipement() != null) { BigDecimal price = categorie.getEquipementPrix(dot.getEquipement().getId()); if (price != null) { prixTotal = prixTotal.add(price); @@ -81,6 +87,50 @@ public class Licence { return prixTotal; } + @Transient + public BigDecimal getEquipementsContrib() { + if (categorie == null) return BigDecimal.ZERO; + BigDecimal tarifCategorie = (adherent != null && adherent.isResidentTalange()) + ? categorie.getTarifBase() + : categorie.getTarifExterieur(); + if (tarifCategorie == null) tarifCategorie = BigDecimal.ZERO; + BigDecimal prixBrut = getPrixBrut(); + BigDecimal contrib = prixBrut.subtract(tarifCategorie); + return contrib.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : contrib; + } + + // Logic for Global Total Price (after discount if applicable) + @Transient + public BigDecimal getPrixTotal() { + BigDecimal prixBrut = getPrixBrut(); + + if (Boolean.TRUE.equals(reductionEducateur)) { + int pct = (pourcentageReductionEducateur != null && pourcentageReductionEducateur >= 1 && pourcentageReductionEducateur <= 100) + ? pourcentageReductionEducateur + : 100; + + if (pct >= 100) { + return BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP); + } else { + BigDecimal multiplier = BigDecimal.valueOf(100 - pct) + .divide(BigDecimal.valueOf(100), 4, java.math.RoundingMode.HALF_UP); + return prixBrut.multiply(multiplier).setScale(2, java.math.RoundingMode.HALF_UP); + } + } + + return prixBrut.setScale(2, java.math.RoundingMode.HALF_UP); + } + + @Transient + public BigDecimal getMontantReduction() { + if (!Boolean.TRUE.equals(reductionEducateur)) { + return BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP); + } + BigDecimal prixBrut = getPrixBrut(); + BigDecimal prixTotal = getPrixTotal(); + return prixBrut.subtract(prixTotal).setScale(2, java.math.RoundingMode.HALF_UP); + } + // Logic for Reste A Payer @Transient public BigDecimal getResteAPayer() { @@ -146,6 +196,12 @@ public class Licence { public java.time.LocalDateTime getSportEasyEmailSentAt() { return sportEasyEmailSentAt; } public void setSportEasyEmailSentAt(java.time.LocalDateTime sportEasyEmailSentAt) { this.sportEasyEmailSentAt = sportEasyEmailSentAt; } + public Boolean getReductionEducateur() { return reductionEducateur != null ? reductionEducateur : false; } + public void setReductionEducateur(Boolean reductionEducateur) { this.reductionEducateur = reductionEducateur; } + + public Integer getPourcentageReductionEducateur() { return pourcentageReductionEducateur != null ? pourcentageReductionEducateur : 100; } + public void setPourcentageReductionEducateur(Integer pourcentageReductionEducateur) { this.pourcentageReductionEducateur = pourcentageReductionEducateur; } + @Transient public boolean isRenouvellement() { return typeDemande != null && ( diff --git a/as-talange-core/src/main/resources/db/migration/V42__add_reduction_educateur_to_licence.sql b/as-talange-core/src/main/resources/db/migration/V42__add_reduction_educateur_to_licence.sql new file mode 100644 index 0000000..bd353b3 --- /dev/null +++ b/as-talange-core/src/main/resources/db/migration/V42__add_reduction_educateur_to_licence.sql @@ -0,0 +1,2 @@ +ALTER TABLE licence ADD COLUMN reduction_educateur BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE licence ADD COLUMN pourcentage_reduction_educateur INT DEFAULT 100; diff --git a/as-talange-core/src/test/java/com/astalange/core/LicenceReductionTest.java b/as-talange-core/src/test/java/com/astalange/core/LicenceReductionTest.java new file mode 100644 index 0000000..dcc647c --- /dev/null +++ b/as-talange-core/src/test/java/com/astalange/core/LicenceReductionTest.java @@ -0,0 +1,98 @@ +package com.astalange.core; + +import com.astalange.core.entity.Adherent; +import com.astalange.core.entity.Categorie; +import com.astalange.core.entity.Licence; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.*; + +class LicenceReductionTest { + + @Test + @DisplayName("Devrait calculer le prix normal sans réduction") + void testPrixSansReduction() { + Categorie cat = new Categorie(); + cat.setTarifBase(new BigDecimal("100.00")); + cat.setTarifExterieur(new BigDecimal("120.00")); + + Adherent adh = new Adherent(); + adh.setResidentTalange(true); + + Licence licence = new Licence(); + licence.setCategorie(cat); + licence.setAdherent(adh); + licence.setReductionEducateur(false); + + assertEquals(new BigDecimal("100.00"), licence.getPrixBrut()); + assertEquals(new BigDecimal("100.00"), licence.getPrixTotal()); + assertEquals(new BigDecimal("0.00"), licence.getMontantReduction()); + assertEquals(new BigDecimal("100.00"), licence.getResteAPayer()); + } + + @Test + @DisplayName("Devrait calculer une réduction de 100% (gratuit)") + void testReduction100Pourcent() { + Categorie cat = new Categorie(); + cat.setTarifBase(new BigDecimal("140.00")); + + Adherent adh = new Adherent(); + adh.setResidentTalange(true); + + Licence licence = new Licence(); + licence.setCategorie(cat); + licence.setAdherent(adh); + licence.setReductionEducateur(true); + licence.setPourcentageReductionEducateur(100); + + assertEquals(new BigDecimal("140.00"), licence.getPrixBrut()); + assertEquals(new BigDecimal("0.00"), licence.getPrixTotal()); + assertEquals(new BigDecimal("140.00"), licence.getMontantReduction()); + assertEquals(new BigDecimal("0.00"), licence.getResteAPayer()); + } + + @Test + @DisplayName("Devrait calculer une réduction partielle (ex: 50%)") + void testReductionPartielle50Pourcent() { + Categorie cat = new Categorie(); + cat.setTarifBase(new BigDecimal("150.00")); + + Adherent adh = new Adherent(); + adh.setResidentTalange(true); + + Licence licence = new Licence(); + licence.setCategorie(cat); + licence.setAdherent(adh); + licence.setReductionEducateur(true); + licence.setPourcentageReductionEducateur(50); + + assertEquals(new BigDecimal("150.00"), licence.getPrixBrut()); + assertEquals(new BigDecimal("75.00"), licence.getPrixTotal()); + assertEquals(new BigDecimal("75.00"), licence.getMontantReduction()); + assertEquals(new BigDecimal("75.00"), licence.getResteAPayer()); + } + + @Test + @DisplayName("Devrait calculer une réduction partielle de 20%") + void testReductionPartielle20Pourcent() { + Categorie cat = new Categorie(); + cat.setTarifBase(new BigDecimal("200.00")); + + Adherent adh = new Adherent(); + adh.setResidentTalange(true); + + Licence licence = new Licence(); + licence.setCategorie(cat); + licence.setAdherent(adh); + licence.setReductionEducateur(true); + licence.setPourcentageReductionEducateur(20); + + assertEquals(new BigDecimal("200.00"), licence.getPrixBrut()); + assertEquals(new BigDecimal("160.00"), licence.getPrixTotal()); + assertEquals(new BigDecimal("40.00"), licence.getMontantReduction()); + assertEquals(new BigDecimal("160.00"), licence.getResteAPayer()); + } +} diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/LicenceController.java b/as-talange-web/src/main/java/com/astalange/web/controller/LicenceController.java index 314e496..0301ee1 100644 --- a/as-talange-web/src/main/java/com/astalange/web/controller/LicenceController.java +++ b/as-talange-web/src/main/java/com/astalange/web/controller/LicenceController.java @@ -50,7 +50,9 @@ public class LicenceController { @RequestParam(required = false) String typeDemande, @RequestParam(required = false) String typeLicence, @RequestParam(required = false) String commentaire, - @RequestParam(required = false) Long equipeId) { + @RequestParam(required = false) Long equipeId, + @RequestParam(required = false, defaultValue = "false") Boolean reductionEducateur, + @RequestParam(required = false, defaultValue = "100") Integer pourcentageReductionEducateur) { Adherent adherent = adherentRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("Invalid Adherent ID")); @@ -75,6 +77,8 @@ public class LicenceController { licence.setTypeDemande(typeDemande); licence.setTypeLicence(typeLicence); licence.setCommentaire(commentaire); + licence.setReductionEducateur(Boolean.TRUE.equals(reductionEducateur)); + licence.setPourcentageReductionEducateur(pourcentageReductionEducateur != null ? pourcentageReductionEducateur : 100); if (equipeId != null) { Equipe equipe = equipeRepository.findById(equipeId) @@ -100,7 +104,9 @@ public class LicenceController { @RequestParam(required = false) String typeDemande, @RequestParam(required = false) String typeLicence, @RequestParam(required = false) String commentaire, - @RequestParam(required = false) Long equipeId) { + @RequestParam(required = false) Long equipeId, + @RequestParam(required = false, defaultValue = "false") Boolean reductionEducateur, + @RequestParam(required = false, defaultValue = "100") Integer pourcentageReductionEducateur) { Licence licence = licenceRepository.findById(licenceId) .orElseThrow(() -> new IllegalArgumentException("Invalid Licence ID")); @@ -114,6 +120,8 @@ public class LicenceController { licence.setTypeDemande(typeDemande); licence.setTypeLicence(typeLicence); licence.setCommentaire(commentaire); + licence.setReductionEducateur(Boolean.TRUE.equals(reductionEducateur)); + licence.setPourcentageReductionEducateur(pourcentageReductionEducateur != null ? pourcentageReductionEducateur : 100); if (equipeId != null) { Equipe equipe = equipeRepository.findById(equipeId) @@ -189,7 +197,7 @@ public class LicenceController { StringBuilder sb = new StringBuilder(); sb.append('\ufeff'); - sb.append("Nom;Prénom;Catégorie;N° Licence;Email;Type de Demande;Saison;Etat\n"); + sb.append("Nom;Prénom;Catégorie;N° Licence;Email;Type de Demande;Réduction Éducateur;Saison;Etat\n"); for (Licence l : licences) { String n = l.getAdherent() != null && l.getAdherent().getNom() != null ? l.getAdherent().getNom() : ""; @@ -198,6 +206,7 @@ public class LicenceController { String num = l.getNumeroLicence() != null ? l.getNumeroLicence() : ""; String e = l.getAdherent() != null && l.getAdherent().getEmail() != null ? l.getAdherent().getEmail() : ""; String td = l.getTypeDemande() != null ? l.getTypeDemande() : ""; + String red = Boolean.TRUE.equals(l.getReductionEducateur()) ? ("-" + l.getPourcentageReductionEducateur() + "%") : "Non"; String s = l.getSaison() != null ? l.getSaison().getNom() : ""; String etat = l.getEtat() != null ? l.getEtat() : ""; @@ -207,6 +216,7 @@ public class LicenceController { .append(escapeCsv(num)).append(";") .append(escapeCsv(e)).append(";") .append(escapeCsv(td)).append(";") + .append(escapeCsv(red)).append(";") .append(escapeCsv(s)).append(";") .append(escapeCsv(etat)).append("\n"); } diff --git a/as-talange-web/src/main/resources/templates/adherents/form.html b/as-talange-web/src/main/resources/templates/adherents/form.html index 1bcbe15..6bf08bc 100644 --- a/as-talange-web/src/main/resources/templates/adherents/form.html +++ b/as-talange-web/src/main/resources/templates/adherents/form.html @@ -226,7 +226,7 @@

Licences de l'adhérent

-
@@ -251,14 +251,14 @@ - 2024-2025 + th:data-tarif-base="${lic.categorie != null ? lic.categorie.tarifBase : 0}" + th:data-tarif-exterieur="${lic.categorie != null ? lic.categorie.tarifExterieur : 0}" + th:data-equipements-contrib="${lic.getEquipementsContrib()}" + th:data-total-paye="${lic.getSommePayee()}"> + 2024-2025 - U15 - 100.00 € (Catégorie) + U15 + 100.00 € (Catégorie)
Nouvelle
@@ -270,23 +270,37 @@ th:classappend="${lic.etat == 'Validée' ? 'bg-blue-100 text-blue-800' : (lic.etat == 'Payée' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800')}" th:text="${lic.etat}">Brouillon - 130.00 € + +
+ Éducateur (-100%) +
+ 150.00 € + 0.00 € +
+
+
+ 130.00 € +
+ 30.00 € -
+
+ + +
@@ -644,7 +671,17 @@