From 5f2bf61829a534e9e3167a96699071ad26341d00 Mon Sep 17 00:00:00 2001 From: Youssef Date: Wed, 24 Jun 2026 23:56:46 +0200 Subject: [PATCH] feat: gestion type de demande, calcul dynamique du tarif et pre-selection equipement (maillot) pour inscription --- .../com/astalange/core/entity/Adherent.java | 12 ++++ .../com/astalange/core/entity/Categorie.java | 29 ++++++++ .../astalange/core/entity/PreInscription.java | 12 ++++ .../core/repository/CategorieRepository.java | 6 ++ .../core/service/CategorieService.java | 15 +++- .../core/service/PreInscriptionService.java | 2 + .../db/migration/V28__add_type_demande.sql | 3 + .../V29__add_demande_to_adherent.sql | 3 + .../web/controller/LicenceController.java | 17 +---- .../PublicInscriptionController.java | 70 ++++++++++++++++++- .../resources/templates/adherents/form.html | 31 +++++++- .../templates/public/formulaire.html | 60 ++++++++++++++++ .../resources/templates/public/succes.html | 51 +++++++++++++- 13 files changed, 292 insertions(+), 19 deletions(-) create mode 100644 as-talange-core/src/main/resources/db/migration/V28__add_type_demande.sql create mode 100644 as-talange-core/src/main/resources/db/migration/V29__add_demande_to_adherent.sql diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/Adherent.java b/as-talange-core/src/main/java/com/astalange/core/entity/Adherent.java index d8a2bda..20deb9b 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/Adherent.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/Adherent.java @@ -41,6 +41,12 @@ public class Adherent { @Column(name = "representant_legal", length = 150) private String representantLegal; + @Column(name = "type_demande", length = 50) + private String typeDemande; + + @Column(name = "ancien_club", length = 150) + private String ancienClub; + private boolean residentTalange = true; @Column(nullable = false, length = 10) @@ -87,6 +93,12 @@ public class Adherent { public String getRepresentantLegal() { return representantLegal; } public void setRepresentantLegal(String representantLegal) { this.representantLegal = representantLegal; } + public String getTypeDemande() { return typeDemande; } + public void setTypeDemande(String typeDemande) { this.typeDemande = typeDemande; } + + public String getAncienClub() { return ancienClub; } + public void setAncienClub(String ancienClub) { this.ancienClub = ancienClub; } + public boolean isResidentTalange() { return residentTalange; } public void setResidentTalange(boolean residentTalange) { this.residentTalange = residentTalange; } diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/Categorie.java b/as-talange-core/src/main/java/com/astalange/core/entity/Categorie.java index 5832694..43e3c5d 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/Categorie.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/Categorie.java @@ -84,4 +84,33 @@ public class Categorie { .map(CategorieEquipement::getPrix) .orElse(BigDecimal.ZERO); } + + @Transient + public BigDecimal getEquipementPrixByNom(String nom) { + if (categorieEquipements == null || nom == null) return BigDecimal.ZERO; + return categorieEquipements.stream() + .filter(ce -> ce.getEquipement() != null && nom.equalsIgnoreCase(ce.getEquipement().getNom())) + .findFirst() + .map(CategorieEquipement::getPrix) + .map(p -> p == null ? BigDecimal.ZERO : p) + .orElse(BigDecimal.ZERO); + } + + @Transient + public boolean isU11OrBelow() { + if (nom == null) return false; + String nomCat = nom.trim().toUpperCase(); + if (nomCat.startsWith("U")) { + java.util.regex.Matcher m = java.util.regex.Pattern.compile("^U(\\d+)").matcher(nomCat); + if (m.find()) { + try { + int age = Integer.parseInt(m.group(1)); + return age <= 11; + } catch (NumberFormatException e) { + return false; + } + } + } + return false; + } } diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/PreInscription.java b/as-talange-core/src/main/java/com/astalange/core/entity/PreInscription.java index 3d1f0ba..7e932b6 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/PreInscription.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/PreInscription.java @@ -52,6 +52,12 @@ public class PreInscription { @Column(name = "consentement_rgpd", nullable = false) private Boolean consentementRgpd = false; + @Column(name = "type_demande", nullable = false, length = 50) + private String typeDemande = "NOUVELLE"; + + @Column(name = "ancien_club", length = 150) + private String ancienClub; + // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } @@ -94,4 +100,10 @@ public class PreInscription { public Boolean getConsentementRgpd() { return consentementRgpd; } public void setConsentementRgpd(Boolean consentementRgpd) { this.consentementRgpd = consentementRgpd; } + + public String getTypeDemande() { return typeDemande; } + public void setTypeDemande(String typeDemande) { this.typeDemande = typeDemande; } + + public String getAncienClub() { return ancienClub; } + public void setAncienClub(String ancienClub) { this.ancienClub = ancienClub; } } diff --git a/as-talange-core/src/main/java/com/astalange/core/repository/CategorieRepository.java b/as-talange-core/src/main/java/com/astalange/core/repository/CategorieRepository.java index 101fa20..b10f9d2 100644 --- a/as-talange-core/src/main/java/com/astalange/core/repository/CategorieRepository.java +++ b/as-talange-core/src/main/java/com/astalange/core/repository/CategorieRepository.java @@ -7,7 +7,13 @@ import org.springframework.stereotype.Repository; import com.astalange.core.entity.Saison; import java.util.List; +import org.springframework.data.repository.query.Param; +import org.springframework.data.jpa.repository.Query; + @Repository public interface CategorieRepository extends JpaRepository { List findBySaison(Saison saison); + + @Query("SELECT c FROM Categorie c WHERE c.saison = :saison AND :annee BETWEEN c.anneeMin AND c.anneeMax") + List findBySaisonAndAnnee(@Param("saison") Saison saison, @Param("annee") Integer annee); } diff --git a/as-talange-core/src/main/java/com/astalange/core/service/CategorieService.java b/as-talange-core/src/main/java/com/astalange/core/service/CategorieService.java index b32ece7..78dddbb 100644 --- a/as-talange-core/src/main/java/com/astalange/core/service/CategorieService.java +++ b/as-talange-core/src/main/java/com/astalange/core/service/CategorieService.java @@ -117,8 +117,21 @@ public class CategorieService { Dotation newDotation = new Dotation(); newDotation.setLicence(licence); newDotation.setEquipement(ce.getEquipement()); - newDotation.setChoisi(ce.getObligatoire()); // By default checked if obligatoire + boolean isMaillot = "Maillot".equalsIgnoreCase(ce.getEquipement().getNom()); + boolean isNouvelleAndU11 = false; + if (licence.getTypeDemande() != null && + (licence.getTypeDemande().equalsIgnoreCase("Nouvelle demande") || licence.getTypeDemande().equalsIgnoreCase("NOUVELLE")) && + licence.getCategorie() != null && + licence.getCategorie().isU11OrBelow()) { + isNouvelleAndU11 = true; + } + newDotation.setChoisi(ce.getObligatoire() || (isMaillot && isNouvelleAndU11)); // Checked if obligatoire or if it's a new registration for U11 or below newDotation.setFourni(false); + newDotation.setTaille(""); + newDotation.setNumero(""); + if (licence.getAdherent() != null) { + newDotation.setFlocage(licence.getAdherent().getNom().toUpperCase() + " " + licence.getAdherent().getPrenom()); + } currentDotations.add(newDotation); } } diff --git a/as-talange-core/src/main/java/com/astalange/core/service/PreInscriptionService.java b/as-talange-core/src/main/java/com/astalange/core/service/PreInscriptionService.java index 737712e..9dd7c0e 100644 --- a/as-talange-core/src/main/java/com/astalange/core/service/PreInscriptionService.java +++ b/as-talange-core/src/main/java/com/astalange/core/service/PreInscriptionService.java @@ -44,6 +44,8 @@ public class PreInscriptionService { adherent.setEmail(pre.getEmail()); adherent.setTelephone(pre.getTelephone()); adherent.setRepresentantLegal(pre.getRepresentantLegal()); + adherent.setTypeDemande(pre.getTypeDemande()); + adherent.setAncienClub(pre.getAncienClub()); // Par défaut adherent.setSexe("MASCULIN"); adherent.setTypeMaillot("JOUEUR"); diff --git a/as-talange-core/src/main/resources/db/migration/V28__add_type_demande.sql b/as-talange-core/src/main/resources/db/migration/V28__add_type_demande.sql new file mode 100644 index 0000000..5c7b380 --- /dev/null +++ b/as-talange-core/src/main/resources/db/migration/V28__add_type_demande.sql @@ -0,0 +1,3 @@ +ALTER TABLE pre_inscription +ADD COLUMN type_demande VARCHAR(50) DEFAULT 'NOUVELLE' NOT NULL, +ADD COLUMN ancien_club VARCHAR(150); diff --git a/as-talange-core/src/main/resources/db/migration/V29__add_demande_to_adherent.sql b/as-talange-core/src/main/resources/db/migration/V29__add_demande_to_adherent.sql new file mode 100644 index 0000000..2c1a28e --- /dev/null +++ b/as-talange-core/src/main/resources/db/migration/V29__add_demande_to_adherent.sql @@ -0,0 +1,3 @@ +ALTER TABLE adherent +ADD COLUMN type_demande VARCHAR(50), +ADD COLUMN ancien_club VARCHAR(150); 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 607e35c..957026c 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 @@ -82,21 +82,8 @@ public class LicenceController { licence = licenceRepository.save(licence); - // Auto-initialize dotations for all configured equipments of the category - List catEquipements = categorie.getCategorieEquipements(); - if (catEquipements != null) { - for (CategorieEquipement ce : catEquipements) { - Dotation dotation = new Dotation(); - dotation.setLicence(licence); - dotation.setEquipement(ce.getEquipement()); - dotation.setTaille(""); - dotation.setFlocage(adherent.getNom().toUpperCase() + " " + adherent.getPrenom()); - dotation.setNumero(""); - dotation.setFourni(false); - dotation.setChoisi(Boolean.TRUE.equals(ce.getObligatoire())); - dotationRepository.save(dotation); - } - } + // Auto-initialize dotations via CategorieService to ensure consistency + categorieService.syncDotationsForLicence(licence); return "redirect:/adherents/" + id + "/edit"; } diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/PublicInscriptionController.java b/as-talange-web/src/main/java/com/astalange/web/controller/PublicInscriptionController.java index 57c7d5d..bf4cff3 100644 --- a/as-talange-web/src/main/java/com/astalange/web/controller/PublicInscriptionController.java +++ b/as-talange-web/src/main/java/com/astalange/web/controller/PublicInscriptionController.java @@ -6,6 +6,8 @@ import com.astalange.core.entity.Saison; import com.astalange.core.repository.PreInscriptionRepository; import com.astalange.core.repository.TokenPreInscriptionRepository; import com.astalange.core.repository.SaisonRepository; +import com.astalange.core.repository.CategorieRepository; +import com.astalange.core.entity.Categorie; import com.astalange.core.service.CaptchaValidationService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -14,7 +16,10 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.beans.factory.annotation.Value; import java.time.LocalDateTime; +import java.time.LocalDate; import java.util.UUID; +import java.util.List; +import java.math.BigDecimal; @Controller @RequestMapping("/inscription-public") @@ -24,15 +29,18 @@ public class PublicInscriptionController { private final TokenPreInscriptionRepository tokenRepository; private final PreInscriptionRepository preInscriptionRepository; private final SaisonRepository saisonRepository; + private final CategorieRepository categorieRepository; public PublicInscriptionController(CaptchaValidationService captchaValidationService, TokenPreInscriptionRepository tokenRepository, PreInscriptionRepository preInscriptionRepository, - SaisonRepository saisonRepository) { + SaisonRepository saisonRepository, + CategorieRepository categorieRepository) { this.captchaValidationService = captchaValidationService; this.tokenRepository = tokenRepository; this.preInscriptionRepository = preInscriptionRepository; this.saisonRepository = saisonRepository; + this.categorieRepository = categorieRepository; } @Value("${captcha.sitekey:1x00000000000000000000AA}") @@ -117,9 +125,69 @@ public class PublicInscriptionController { token.setEstUtilise(true); tokenRepository.save(token); + if ("NOUVELLE".equals(preInscription.getTypeDemande())) { + String tarifStr = "210 €"; // Default + if (preInscription.getDateNaissance() != null) { + int annee = preInscription.getDateNaissance().getYear(); + List categories = categorieRepository.findBySaisonAndAnnee(activeSaison, annee); + if (!categories.isEmpty()) { + Categorie cat = categories.get(0); + if (cat.getTarifBase() != null) { + BigDecimal prixMaillot = BigDecimal.ZERO; + if (cat.isU11OrBelow()) { + prixMaillot = cat.getEquipementPrixByNom("Maillot"); + } + BigDecimal tarifTotal = cat.getTarifBase().add(prixMaillot); + tarifStr = tarifTotal.intValue() + " €"; + } + } + } + + redirectAttributes.addFlashAttribute("prenom", preInscription.getPrenom()); + redirectAttributes.addFlashAttribute("tarif", tarifStr); + redirectAttributes.addFlashAttribute("documents", java.util.Arrays.asList( + "Photo d’identité", + "Carte d’identité ou passeport de l’enfant", + "Livret de famille (si pas de pièce d’identité)", + "Adresse e-mail du représentant légal", + "Pour les enfants nés à l’étranger : passeport + justificatif de domicile des parents" + )); + redirectAttributes.addFlashAttribute("isNouvelle", true); + } + return "redirect:/inscription-public/succes"; } + @GetMapping("/api/tarif") + @ResponseBody + public String getTarif(@RequestParam(value = "dateNaissance", required = false) String dateNaissanceStr) { + if (dateNaissanceStr == null || dateNaissanceStr.isEmpty()) { + return "210 €"; + } + try { + LocalDate dateNaissance = LocalDate.parse(dateNaissanceStr); + int annee = dateNaissance.getYear(); + Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null); + if (activeSaison == null) return "210 €"; + + List categories = categorieRepository.findBySaisonAndAnnee(activeSaison, annee); + if (categories.isEmpty()) return "210 €"; + + Categorie cat = categories.get(0); + if (cat.getTarifBase() != null) { + BigDecimal prixMaillot = BigDecimal.ZERO; + if (cat.isU11OrBelow()) { + prixMaillot = cat.getEquipementPrixByNom("Maillot"); + } + BigDecimal tarifTotal = cat.getTarifBase().add(prixMaillot); + return tarifTotal.intValue() + " €"; + } + } catch (Exception e) { + // Return default on error + } + return "210 €"; + } + @GetMapping("/succes") public String showSucces() { return "public/succes"; 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 9388603..50b06f2 100644 --- a/as-talange-web/src/main/resources/templates/adherents/form.html +++ b/as-talange-web/src/main/resources/templates/adherents/form.html @@ -148,6 +148,24 @@ +
+ +
+ + +
+ + +
+ + +

+
+
+
@@ -549,7 +567,18 @@ form.action = '/adherents/' + adherentId + '/licences'; document.getElementById('numeroLicenceInput').value = ''; document.getElementById('etatSelect').value = 'Brouillon'; - document.getElementById('typeDemandeSelect').value = ''; + + // Pré-remplissage du type de demande + const adherentTypeDemande = document.getElementById('typeDemande') ? document.getElementById('typeDemande').value : ''; + const typeDemandeSelect = document.getElementById('typeDemandeSelect'); + if (adherentTypeDemande === 'NOUVELLE') { + typeDemandeSelect.value = 'Nouvelle demande'; + } else if (adherentTypeDemande === 'RENOUVELLEMENT') { + typeDemandeSelect.value = 'Renouvellement'; + } else { + typeDemandeSelect.value = ''; + } + document.getElementById('typeLicenceSelect').value = ''; // Pré-sélection de la catégorie selon l'année de naissance diff --git a/as-talange-web/src/main/resources/templates/public/formulaire.html b/as-talange-web/src/main/resources/templates/public/formulaire.html index e382f5d..d3a2143 100644 --- a/as-talange-web/src/main/resources/templates/public/formulaire.html +++ b/as-talange-web/src/main/resources/templates/public/formulaire.html @@ -14,9 +14,50 @@

Formulaire de pré-inscription

Veuillez remplir les informations concernant le futur licencié.

+
+

Information sur le type de demande

+
    +
  • Nouvelle licence : Concerne les personnes qui n'étaient pas inscrites au club la saison précédente.
  • +
  • Renouvellement : Réservé aux personnes déjà inscrites au club la saison précédente.
  • +
+
+
+
+ +
+ + +
+
+ + +
@@ -88,6 +129,25 @@
Inscription réussie @@ -16,8 +17,56 @@

Pré-inscription envoyée !

-

Votre dossier a bien été transmis au secrétariat de l'AS Talange.

+

Votre dossier a bien été transmis au secrétariat de l'AS Talange.

Un responsable va traiter votre demande prochainement. Vous pouvez fermer cette page.

+ +
+
+ +
+
+ +

Mémo Inscription

+ +
+

Tarif Licence : 210 €

+
+ +

Documents à fournir :

+
    +
  • + + Document +
  • +
+

Ces documents sont à fournir au secrétariat du club pour finaliser l'inscription.

+
+

As Talange

+
+
+ +
+ +
+
+ +