From bca84be16a8c9dc9677273675ddc1277d856543f Mon Sep 17 00:00:00 2001 From: Youssef Date: Thu, 11 Jun 2026 22:57:16 +0200 Subject: [PATCH] Refactor: Move equipment price and mandatory status to Categorie relationship - Created CategorieEquipement entity to act as a join table between Category and Equipment. - Moved 'obligatoire' and 'prix' (formerly prixContribution) fields from Equipement to the new CategorieEquipement entity. - Added Flyway migrations V14 and V15 to update the database schema and migrate existing data. - Updated Categorie UI to use a select dropdown and price input for managing category-specific equipment configurations. - Replaced 'equipement.obligatoire' and 'equipement.prixContribution' calls with their new category-level equivalents in logic and templates. - Updated pricing calculation in Licence entity to source prices dynamically from the Categorie configuration. - Updated Dotation generation logic to sync with category requirements automatically. --- .../com/astalange/core/entity/Categorie.java | 30 +++++ .../core/entity/CategorieEquipement.java | 43 ++++++ .../com/astalange/core/entity/Equipement.java | 11 -- .../com/astalange/core/entity/Licence.java | 2 +- .../core/repository/LicenceRepository.java | 2 + .../core/service/CategorieService.java | 122 ++++++++++++++++++ .../astalange/core/service/SaisonService.java | 23 +++- ...V14__add_categorie_equipement_relation.sql | 18 +++ ...V15__move_prix_to_categorie_equipement.sql | 9 ++ .../web/controller/CategorieController.java | 45 ++++++- .../web/controller/DotationController.java | 4 +- .../web/controller/EquipementController.java | 17 ++- .../web/controller/LicenceController.java | 28 ++-- .../resources/templates/adherents/form.html | 8 +- .../parametrage/categories_form.html | 26 ++++ .../parametrage/equipements_form.html | 12 +- .../parametrage/equipements_list.html | 10 +- 17 files changed, 351 insertions(+), 59 deletions(-) create mode 100644 as-talange-core/src/main/java/com/astalange/core/entity/CategorieEquipement.java create mode 100644 as-talange-core/src/main/java/com/astalange/core/service/CategorieService.java create mode 100644 as-talange-core/src/main/resources/db/migration/V14__add_categorie_equipement_relation.sql create mode 100644 as-talange-core/src/main/resources/db/migration/V15__move_prix_to_categorie_equipement.sql 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 a93775b..896b707 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 @@ -2,6 +2,8 @@ package com.astalange.core.entity; import jakarta.persistence.*; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; @Entity @Table(name = "categorie") @@ -30,6 +32,9 @@ public class Categorie { @JoinColumn(name = "saison_id", nullable = false) private Saison saison; + @OneToMany(mappedBy = "categorie", cascade = CascadeType.ALL, orphanRemoval = true) + private List categorieEquipements = new ArrayList<>(); + // Getters and Setters public Long getId() { return id; } @@ -52,4 +57,29 @@ public class Categorie { public Saison getSaison() { return saison; } public void setSaison(Saison saison) { this.saison = saison; } + + public List getCategorieEquipements() { return categorieEquipements; } + public void setCategorieEquipements(List categorieEquipements) { this.categorieEquipements = categorieEquipements; } + + @Transient + public boolean hasEquipement(Long equipementId) { + if (categorieEquipements == null) return false; + return categorieEquipements.stream().anyMatch(ce -> ce.getEquipement() != null && ce.getEquipement().getId().equals(equipementId)); + } + + @Transient + public boolean isEquipementObligatoire(Long equipementId) { + if (categorieEquipements == null) return false; + return categorieEquipements.stream().anyMatch(ce -> ce.getEquipement() != null && ce.getEquipement().getId().equals(equipementId) && Boolean.TRUE.equals(ce.getObligatoire())); + } + + @Transient + public BigDecimal getEquipementPrix(Long equipementId) { + if (categorieEquipements == null) return BigDecimal.ZERO; + return categorieEquipements.stream() + .filter(ce -> ce.getEquipement() != null && ce.getEquipement().getId().equals(equipementId)) + .findFirst() + .map(CategorieEquipement::getPrix) + .orElse(BigDecimal.ZERO); + } } diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/CategorieEquipement.java b/as-talange-core/src/main/java/com/astalange/core/entity/CategorieEquipement.java new file mode 100644 index 0000000..e2a5c7e --- /dev/null +++ b/as-talange-core/src/main/java/com/astalange/core/entity/CategorieEquipement.java @@ -0,0 +1,43 @@ +package com.astalange.core.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "categorie_equipement") +public class CategorieEquipement { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "categorie_id", nullable = false) + private Categorie categorie; + + @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "equipement_id", nullable = false) + private Equipement equipement; + + @Column(nullable = false) + private Boolean obligatoire = false; + + @Column(nullable = false, precision = 10, scale = 2) + private java.math.BigDecimal prix = java.math.BigDecimal.ZERO; + + // Getters and Setters + + public java.math.BigDecimal getPrix() { return prix; } + public void setPrix(java.math.BigDecimal prix) { this.prix = prix; } + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public Categorie getCategorie() { return categorie; } + public void setCategorie(Categorie categorie) { this.categorie = categorie; } + + public Equipement getEquipement() { return equipement; } + public void setEquipement(Equipement equipement) { this.equipement = equipement; } + + public Boolean getObligatoire() { return obligatoire; } + public void setObligatoire(Boolean obligatoire) { this.obligatoire = obligatoire; } +} diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/Equipement.java b/as-talange-core/src/main/java/com/astalange/core/entity/Equipement.java index e1b8c83..baf8050 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/Equipement.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/Equipement.java @@ -17,11 +17,6 @@ public class Equipement { @Column(columnDefinition = "TEXT") private String description; - @Column(nullable = false) - private Boolean obligatoire = false; - - @Column(name = "prix_contribution", nullable = false, precision = 10, scale = 2) - private BigDecimal prixContribution = BigDecimal.ZERO; @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "saison_id", nullable = false) @@ -38,12 +33,6 @@ public class Equipement { public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } - public Boolean getObligatoire() { return obligatoire; } - public void setObligatoire(Boolean obligatoire) { this.obligatoire = obligatoire; } - - public BigDecimal getPrixContribution() { return prixContribution; } - public void setPrixContribution(BigDecimal prixContribution) { this.prixContribution = prixContribution; } - public Saison getSaison() { return saison; } public void setSaison(Saison saison) { this.saison = saison; } } 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 93715ff..69cd95d 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 @@ -55,7 +55,7 @@ public class Licence { if (dotations != null) { for (Dotation dot : dotations) { if (dot.getChoisi() && dot.getEquipement() != null) { - BigDecimal price = dot.getEquipement().getPrixContribution(); + BigDecimal price = categorie.getEquipementPrix(dot.getEquipement().getId()); if (price != null) { prixTotal = prixTotal.add(price); } diff --git a/as-talange-core/src/main/java/com/astalange/core/repository/LicenceRepository.java b/as-talange-core/src/main/java/com/astalange/core/repository/LicenceRepository.java index d0a2a37..9188bef 100644 --- a/as-talange-core/src/main/java/com/astalange/core/repository/LicenceRepository.java +++ b/as-talange-core/src/main/java/com/astalange/core/repository/LicenceRepository.java @@ -11,6 +11,8 @@ import java.util.List; @Repository public interface LicenceRepository extends JpaRepository { List findByAdherentId(Long adherentId); + + List findBySaisonAndCategorie(com.astalange.core.entity.Saison saison, com.astalange.core.entity.Categorie categorie); long countByEtat(String etat); 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 new file mode 100644 index 0000000..ee55fe0 --- /dev/null +++ b/as-talange-core/src/main/java/com/astalange/core/service/CategorieService.java @@ -0,0 +1,122 @@ +package com.astalange.core.service; + +import com.astalange.core.entity.*; +import com.astalange.core.repository.*; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class CategorieService { + + private final CategorieRepository categorieRepository; + private final SaisonRepository saisonRepository; + private final EquipementRepository equipementRepository; + private final LicenceRepository licenceRepository; + + public CategorieService(CategorieRepository categorieRepository, SaisonRepository saisonRepository, EquipementRepository equipementRepository, LicenceRepository licenceRepository) { + this.categorieRepository = categorieRepository; + this.saisonRepository = saisonRepository; + this.equipementRepository = equipementRepository; + this.licenceRepository = licenceRepository; + } + + public record EquipementConfig(boolean obligatoire, java.math.BigDecimal prix) {} + + @Transactional + public void saveCategorie(Categorie categorie, java.util.Map equipementConfigs) { + Saison activeSaison; + Categorie existing = null; + if (categorie.getId() == null) { + activeSaison = saisonRepository.findByEstActiveTrue() + .orElseThrow(() -> new IllegalStateException("Aucune saison active trouvée")); + categorie.setSaison(activeSaison); + } else { + final Long catId = categorie.getId(); + existing = categorieRepository.findById(catId) + .orElseThrow(() -> new IllegalArgumentException("Invalid category ID: " + catId)); + categorie.setSaison(existing.getSaison()); + activeSaison = existing.getSaison(); + } + + // Handle CategorieEquipement + if (existing != null) { + categorie.getCategorieEquipements().clear(); + categorie.getCategorieEquipements().addAll(existing.getCategorieEquipements()); + } + + List nouveauxEquipements = new ArrayList<>(); + if (equipementConfigs != null) { + for (java.util.Map.Entry entry : equipementConfigs.entrySet()) { + Long eqId = entry.getKey(); + EquipementConfig config = entry.getValue(); + Equipement eq = equipementRepository.findById(eqId).orElse(null); + if (eq != null) { + CategorieEquipement ce = new CategorieEquipement(); + ce.setCategorie(categorie); + ce.setEquipement(eq); + ce.setObligatoire(config.obligatoire()); + ce.setPrix(config.prix() != null ? config.prix() : java.math.BigDecimal.ZERO); + nouveauxEquipements.add(ce); + } + } + } + + categorie.getCategorieEquipements().clear(); + categorie.getCategorieEquipements().addAll(nouveauxEquipements); + + categorie = categorieRepository.save(categorie); + + // Mettre à jour les adhérents (via les licences de la saison actuelle) + List licences = licenceRepository.findBySaisonAndCategorie(activeSaison, categorie); + for (Licence licence : licences) { + updateDotationsForLicence(licence, nouveauxEquipements); + } + } + + private void updateDotationsForLicence(Licence licence, List categorieEquipements) { + List currentDotations = licence.getDotations(); + List toRemove = new ArrayList<>(); + + // Remove dotations for equipements no longer in the category + for (Dotation d : currentDotations) { + boolean found = false; + for (CategorieEquipement ce : categorieEquipements) { + if (ce.getEquipement().getId().equals(d.getEquipement().getId())) { + found = true; + break; + } + } + if (!found) { + toRemove.add(d); + } + } + currentDotations.removeAll(toRemove); + + // Add missing dotations + for (CategorieEquipement ce : categorieEquipements) { + boolean found = false; + for (Dotation d : currentDotations) { + if (ce.getEquipement().getId().equals(d.getEquipement().getId())) { + found = true; + if (Boolean.TRUE.equals(ce.getObligatoire()) && !Boolean.TRUE.equals(d.getChoisi())) { + d.setChoisi(true); + } + break; + } + } + if (!found) { + Dotation newDotation = new Dotation(); + newDotation.setLicence(licence); + newDotation.setEquipement(ce.getEquipement()); + newDotation.setChoisi(ce.getObligatoire()); // By default checked if obligatoire + newDotation.setFourni(false); + currentDotations.add(newDotation); + } + } + + licenceRepository.save(licence); + } +} diff --git a/as-talange-core/src/main/java/com/astalange/core/service/SaisonService.java b/as-talange-core/src/main/java/com/astalange/core/service/SaisonService.java index bf32ea7..92e5c3a 100644 --- a/as-talange-core/src/main/java/com/astalange/core/service/SaisonService.java +++ b/as-talange-core/src/main/java/com/astalange/core/service/SaisonService.java @@ -53,14 +53,15 @@ public class SaisonService { private void dupliquerParametrages(Saison ancienneSaison, Saison nouvelleSaison) { // 1. Dupliquer les équipements List anciensEquipements = equipementRepository.findBySaison(ancienneSaison); + java.util.Map oldToNewEquipementMap = new java.util.HashMap<>(); + for (Equipement ancien : anciensEquipements) { Equipement nouvelEquipement = new Equipement(); nouvelEquipement.setNom(ancien.getNom()); nouvelEquipement.setDescription(ancien.getDescription()); - nouvelEquipement.setObligatoire(ancien.getObligatoire()); - nouvelEquipement.setPrixContribution(ancien.getPrixContribution()); nouvelEquipement.setSaison(nouvelleSaison); - equipementRepository.save(nouvelEquipement); + nouvelEquipement = equipementRepository.save(nouvelEquipement); + oldToNewEquipementMap.put(ancien.getId(), nouvelEquipement); } // 2. Dupliquer les catégories (avec incrémentation de l'année) @@ -78,6 +79,22 @@ public class SaisonService { nouvelleCategorie.setTarifBase(ancienne.getTarifBase()); nouvelleCategorie.setTarifExterieur(ancienne.getTarifExterieur()); nouvelleCategorie.setSaison(nouvelleSaison); + + // Dupliquer les relations avec les équipements + if (ancienne.getCategorieEquipements() != null) { + for (com.astalange.core.entity.CategorieEquipement oldCatEq : ancienne.getCategorieEquipements()) { + Equipement newEq = oldToNewEquipementMap.get(oldCatEq.getEquipement().getId()); + if (newEq != null) { + com.astalange.core.entity.CategorieEquipement newCatEq = new com.astalange.core.entity.CategorieEquipement(); + newCatEq.setCategorie(nouvelleCategorie); + newCatEq.setEquipement(newEq); + newCatEq.setObligatoire(oldCatEq.getObligatoire()); + newCatEq.setPrix(oldCatEq.getPrix()); + nouvelleCategorie.getCategorieEquipements().add(newCatEq); + } + } + } + categorieRepository.save(nouvelleCategorie); } } diff --git a/as-talange-core/src/main/resources/db/migration/V14__add_categorie_equipement_relation.sql b/as-talange-core/src/main/resources/db/migration/V14__add_categorie_equipement_relation.sql new file mode 100644 index 0000000..3e00471 --- /dev/null +++ b/as-talange-core/src/main/resources/db/migration/V14__add_categorie_equipement_relation.sql @@ -0,0 +1,18 @@ +CREATE TABLE categorie_equipement ( + id BIGSERIAL PRIMARY KEY, + categorie_id BIGINT NOT NULL, + equipement_id BIGINT NOT NULL, + obligatoire BOOLEAN NOT NULL DEFAULT false, + CONSTRAINT fk_cat_equip_categorie FOREIGN KEY (categorie_id) REFERENCES categorie(id) ON DELETE CASCADE, + CONSTRAINT fk_cat_equip_equipement FOREIGN KEY (equipement_id) REFERENCES equipement(id) ON DELETE CASCADE +); + +-- Migrer les données existantes : associer tous les équipements d'une saison à toutes les catégories de la même saison +-- et transférer la valeur "obligatoire" de l'équipement vers la nouvelle table de liaison +INSERT INTO categorie_equipement (categorie_id, equipement_id, obligatoire) +SELECT c.id, e.id, e.obligatoire +FROM categorie c +JOIN equipement e ON c.saison_id = e.saison_id; + +-- Supprimer la colonne "obligatoire" de la table équipement +ALTER TABLE equipement DROP COLUMN obligatoire; diff --git a/as-talange-core/src/main/resources/db/migration/V15__move_prix_to_categorie_equipement.sql b/as-talange-core/src/main/resources/db/migration/V15__move_prix_to_categorie_equipement.sql new file mode 100644 index 0000000..32ec55c --- /dev/null +++ b/as-talange-core/src/main/resources/db/migration/V15__move_prix_to_categorie_equipement.sql @@ -0,0 +1,9 @@ +ALTER TABLE categorie_equipement ADD COLUMN prix NUMERIC(10,2) NOT NULL DEFAULT 0; + +-- Migrer les données existantes +UPDATE categorie_equipement ce +SET prix = e.prix_contribution +FROM equipement e +WHERE ce.equipement_id = e.id; + +ALTER TABLE equipement DROP COLUMN IF EXISTS prix_contribution; diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/CategorieController.java b/as-talange-web/src/main/java/com/astalange/web/controller/CategorieController.java index 4237fca..537b2c6 100644 --- a/as-talange-web/src/main/java/com/astalange/web/controller/CategorieController.java +++ b/as-talange-web/src/main/java/com/astalange/web/controller/CategorieController.java @@ -1,19 +1,31 @@ package com.astalange.web.controller; import com.astalange.core.entity.Categorie; +import com.astalange.core.entity.Saison; import com.astalange.core.repository.CategorieRepository; +import com.astalange.core.repository.SaisonRepository; +import com.astalange.core.repository.EquipementRepository; +import com.astalange.core.service.CategorieService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Controller @RequestMapping("/categories") public class CategorieController { private final CategorieRepository categorieRepository; + private final SaisonRepository saisonRepository; + private final EquipementRepository equipementRepository; + private final CategorieService categorieService; - public CategorieController(CategorieRepository categorieRepository) { + public CategorieController(CategorieRepository categorieRepository, SaisonRepository saisonRepository, EquipementRepository equipementRepository, CategorieService categorieService) { this.categorieRepository = categorieRepository; + this.saisonRepository = saisonRepository; + this.equipementRepository = equipementRepository; + this.categorieService = categorieService; } @GetMapping @@ -25,6 +37,8 @@ public class CategorieController { @GetMapping("/new") public String showCreateForm(Model model) { model.addAttribute("categorie", new Categorie()); + Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null); + model.addAttribute("allEquipements", activeSaison != null ? equipementRepository.findBySaison(activeSaison) : List.of()); return "parametrage/categories_form"; } @@ -33,12 +47,37 @@ public class CategorieController { Categorie categorie = categorieRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("Invalid category ID: " + id)); model.addAttribute("categorie", categorie); + Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null); + model.addAttribute("allEquipements", activeSaison != null ? equipementRepository.findBySaison(activeSaison) : List.of()); return "parametrage/categories_form"; } @PostMapping - public String saveCategorie(@ModelAttribute("categorie") Categorie categorie) { - categorieRepository.save(categorie); + public String saveCategorie(@ModelAttribute("categorie") Categorie categorie, + jakarta.servlet.http.HttpServletRequest request) { + + java.util.Map configs = new java.util.HashMap<>(); + + request.getParameterMap().forEach((key, values) -> { + if (key.startsWith("etatEquipement_") && values.length > 0) { + String idStr = key.substring("etatEquipement_".length()); + try { + Long eqId = Long.parseLong(idStr); + String etat = values[0]; + if (!"NON_LIE".equals(etat)) { + boolean obligatoire = "OBLIGATOIRE".equals(etat); + String prixStr = request.getParameter("prixEquipement_" + eqId); + java.math.BigDecimal prix = java.math.BigDecimal.ZERO; + if (prixStr != null && !prixStr.trim().isEmpty()) { + prix = new java.math.BigDecimal(prixStr.trim()); + } + configs.put(eqId, new com.astalange.core.service.CategorieService.EquipementConfig(obligatoire, prix)); + } + } catch (NumberFormatException ignored) {} + } + }); + + categorieService.saveCategorie(categorie, configs); return "redirect:/categories"; } diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/DotationController.java b/as-talange-web/src/main/java/com/astalange/web/controller/DotationController.java index e3742e6..24bb2b2 100644 --- a/as-talange-web/src/main/java/com/astalange/web/controller/DotationController.java +++ b/as-talange-web/src/main/java/com/astalange/web/controller/DotationController.java @@ -38,7 +38,7 @@ public class DotationController { dotation.setNumero(numero); dotation.setFourni(fourni != null && fourni); - if (dotation.getEquipement().getObligatoire()) { + if (dotation.getLicence().getCategorie().isEquipementObligatoire(dotation.getEquipement().getId())) { dotation.setChoisi(true); } else { dotation.setChoisi(choisi != null && choisi); @@ -70,7 +70,7 @@ public class DotationController { if (numero != null) dotation.setNumero(numero); if (flocage != null) dotation.setFlocage(flocage); - if (dotation.getEquipement().getObligatoire()) { + if (dotation.getLicence().getCategorie().isEquipementObligatoire(dotation.getEquipement().getId())) { dotation.setChoisi(true); } else { dotation.setChoisi(choisiParam != null); diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/EquipementController.java b/as-talange-web/src/main/java/com/astalange/web/controller/EquipementController.java index 6329b21..f529da0 100644 --- a/as-talange-web/src/main/java/com/astalange/web/controller/EquipementController.java +++ b/as-talange-web/src/main/java/com/astalange/web/controller/EquipementController.java @@ -1,7 +1,9 @@ package com.astalange.web.controller; import com.astalange.core.entity.Equipement; +import com.astalange.core.entity.Saison; import com.astalange.core.repository.EquipementRepository; +import com.astalange.core.repository.SaisonRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; @@ -11,9 +13,11 @@ import org.springframework.web.bind.annotation.*; public class EquipementController { private final EquipementRepository equipementRepository; + private final SaisonRepository saisonRepository; - public EquipementController(EquipementRepository equipementRepository) { + public EquipementController(EquipementRepository equipementRepository, SaisonRepository saisonRepository) { this.equipementRepository = equipementRepository; + this.saisonRepository = saisonRepository; } @GetMapping @@ -38,8 +42,15 @@ public class EquipementController { @PostMapping public String saveEquipement(@ModelAttribute("equipement") Equipement equipement) { - if (equipement.getObligatoire() == null) { - equipement.setObligatoire(false); + + if (equipement.getId() == null) { + Saison activeSaison = saisonRepository.findByEstActiveTrue() + .orElseThrow(() -> new IllegalStateException("Aucune saison active trouvée")); + equipement.setSaison(activeSaison); + } else { + Equipement existing = equipementRepository.findById(equipement.getId()) + .orElseThrow(() -> new IllegalArgumentException("Invalid equipment ID: " + equipement.getId())); + equipement.setSaison(existing.getSaison()); } equipementRepository.save(equipement); return "redirect:/equipements"; 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 13e0fdd..9680f2f 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 @@ -6,10 +6,12 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Controller +@Transactional public class LicenceController { private final AdherentRepository adherentRepository; @@ -73,18 +75,20 @@ public class LicenceController { licence = licenceRepository.save(licence); - // Auto-initialize dotations for all configured equipments of the active season - List equipements = equipementRepository.findBySaison(saisonActive); - for (Equipement eq : equipements) { - Dotation dotation = new Dotation(); - dotation.setLicence(licence); - dotation.setEquipement(eq); - dotation.setTaille(""); - dotation.setFlocage(adherent.getNom().toUpperCase() + " " + adherent.getPrenom()); - dotation.setNumero(""); - dotation.setFourni(false); - dotation.setChoisi(eq.getObligatoire()); - dotationRepository.save(dotation); + // 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); + } } return "redirect:/adherents/" + id + "/edit"; 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 15e52a1..2a13e7b 100644 --- a/as-talange-web/src/main/resources/templates/adherents/form.html +++ b/as-talange-web/src/main/resources/templates/adherents/form.html @@ -282,8 +282,8 @@
Maillot Obligatoire + th:classappend="${dot.licence.categorie.isEquipementObligatoire(dot.equipement.id) ? 'bg-red-50 text-red-700 border border-red-100' : 'bg-gray-50 text-gray-600 border border-gray-100'}" + th:text="${dot.licence.categorie.isEquipementObligatoire(dot.equipement.id) ? 'Obligatoire' : 'Facultatif'}">Obligatoire
Description
@@ -306,10 +306,10 @@
-
+
diff --git a/as-talange-web/src/main/resources/templates/parametrage/categories_form.html b/as-talange-web/src/main/resources/templates/parametrage/categories_form.html index 6f6d43c..9fdd594 100644 --- a/as-talange-web/src/main/resources/templates/parametrage/categories_form.html +++ b/as-talange-web/src/main/resources/templates/parametrage/categories_form.html @@ -50,6 +50,32 @@
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+
+
+
Annuler diff --git a/as-talange-web/src/main/resources/templates/parametrage/equipements_form.html b/as-talange-web/src/main/resources/templates/parametrage/equipements_form.html index 69f0a7d..1d41f48 100644 --- a/as-talange-web/src/main/resources/templates/parametrage/equipements_form.html +++ b/as-talange-web/src/main/resources/templates/parametrage/equipements_form.html @@ -31,18 +31,8 @@
-
- - -

Si l'équipement est facultatif, ce montant sera ajouté au tarif global de la licence s'il est commandé.

-
-
- - -
+
Annuler diff --git a/as-talange-web/src/main/resources/templates/parametrage/equipements_list.html b/as-talange-web/src/main/resources/templates/parametrage/equipements_list.html index bf1f93e..f037a0a 100644 --- a/as-talange-web/src/main/resources/templates/parametrage/equipements_list.html +++ b/as-talange-web/src/main/resources/templates/parametrage/equipements_list.html @@ -30,24 +30,16 @@ Nom de l'équipement Description - Obligatoire - Prix Contribution Actions - Aucun équipement n'est paramétré. + Aucun équipement n'est paramétré. Maillot Maillot de match officiel - - Oui - - 30 € Modifier