diff --git a/as-talange-core/pom.xml b/as-talange-core/pom.xml index 5f80c92..2b7214b 100644 --- a/as-talange-core/pom.xml +++ b/as-talange-core/pom.xml @@ -61,5 +61,11 @@ 1.77 + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/as-talange-core/src/test/java/com/astalange/core/AdherentRecalculationTest.java b/as-talange-core/src/test/java/com/astalange/core/AdherentRecalculationTest.java new file mode 100644 index 0000000..2f1db6f --- /dev/null +++ b/as-talange-core/src/test/java/com/astalange/core/AdherentRecalculationTest.java @@ -0,0 +1,93 @@ +package com.astalange.core; + +import com.astalange.core.entity.*; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class AdherentRecalculationTest { + + @Test + public void testLicencePriceCalculationBasedOnResidencyAndCategory() { + Adherent adherent = new Adherent(); + adherent.setNom("Doe"); + adherent.setPrenom("John"); + adherent.setDateNaissance(LocalDate.of(2015, 5, 10)); // born 2015 + adherent.setResidentTalange(true); + + Categorie u11 = new Categorie(); + u11.setNom("U11"); + u11.setAnneeMin(2015); + u11.setAnneeMax(2015); + u11.setTarifBase(new BigDecimal("130.00")); + u11.setTarifExterieur(new BigDecimal("160.00")); + + Licence licence = new Licence(); + licence.setAdherent(adherent); + licence.setCategorie(u11); + + // Under residentTalange = true, base price should be 130 + assertEquals(new BigDecimal("130.00"), licence.getPrixTotal()); + + // Under residentTalange = false, base price should be 160 + adherent.setResidentTalange(false); + assertEquals(new BigDecimal("160.00"), licence.getPrixTotal()); + } + + @Test + public void testCategoryUpdateOnBirthdateChangeSimulation() { + // Set up adherent + Adherent adherent = new Adherent(); + adherent.setDateNaissance(LocalDate.of(2015, 5, 10)); // 2015 birth year + + Saison saison = new Saison(); + saison.setNom("2025-2026"); + saison.setEstActive(true); + + // Set up categories + Categorie u11 = new Categorie(); + u11.setNom("U11"); + u11.setAnneeMin(2015); + u11.setAnneeMax(2015); + u11.setSaison(saison); + u11.setTarifBase(new BigDecimal("130.00")); + + Categorie u12 = new Categorie(); + u12.setNom("U12"); + u12.setAnneeMin(2014); + u12.setAnneeMax(2014); + u12.setSaison(saison); + u12.setTarifBase(new BigDecimal("140.00")); + + List categories = List.of(u11, u12); + + // Licence initially created for U11 + Licence licence = new Licence(); + licence.setAdherent(adherent); + licence.setCategorie(u11); + licence.setSaison(saison); + + // Simulation of date of birth changing to 2014 (U12) + adherent.setDateNaissance(LocalDate.of(2014, 5, 10)); + int newBirthYear = adherent.getDateNaissance().getYear(); + + // Simulate Controller's update logic + Categorie newCat = categories.stream() + .filter(c -> newBirthYear >= c.getAnneeMin() && newBirthYear <= c.getAnneeMax()) + .findFirst() + .orElse(null); + + assertNotNull(newCat); + assertEquals("U12", newCat.getNom()); + licence.setCategorie(newCat); + + // Verify the licence's category has updated to U12 + assertEquals("U12", licence.getCategorie().getNom()); + // Verify price total is updated dynamically + assertEquals(new BigDecimal("140.00"), licence.getPrixTotal()); + } +} 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 d49b40f..6bbd1b4 100644 --- a/as-talange-web/src/main/resources/templates/adherents/form.html +++ b/as-talange-web/src/main/resources/templates/adherents/form.html @@ -322,8 +322,11 @@ @@ -443,6 +446,7 @@ document.addEventListener("DOMContentLoaded", function() { const dateInput = document.getElementById('dateNaissance'); const repBlock = document.getElementById('representantBlock'); + const residentCheckbox = document.getElementById('residentTalange'); function calculateAge(birthday) { const ageDifMs = Date.now() - birthday.getTime(); @@ -464,7 +468,92 @@ } } - dateInput.addEventListener('change', updateRepresentantBlock); + function updateLicencesCategoryAndPrices() { + if (!dateInput.value) return; + const dob = new Date(dateInput.value); + const birthYear = dob.getFullYear(); + const isResident = residentCheckbox ? residentCheckbox.checked : true; + + const categories = []; + const catSelect = document.getElementById('categorieSelect'); + if (catSelect) { + Array.from(catSelect.options).forEach(opt => { + const id = opt.value; + const nom = opt.getAttribute('data-nom'); + const min = parseInt(opt.getAttribute('data-annee-min')); + const max = parseInt(opt.getAttribute('data-annee-max')); + const tarifBase = parseFloat(opt.getAttribute('data-tarif-base') || '0'); + const tarifExterieur = parseFloat(opt.getAttribute('data-tarif-exterieur') || '0'); + if (id) { + categories.push({ id, nom, min, max, tarifBase, tarifExterieur }); + } + }); + } + + if (categories.length === 0) return; + + const matchingCat = categories.find(c => birthYear >= c.min && birthYear <= c.max); + if (!matchingCat) return; + + document.querySelectorAll('.licence-row').forEach(row => { + row.setAttribute('data-tarif-base', matchingCat.tarifBase); + row.setAttribute('data-tarif-exterieur', matchingCat.tarifExterieur); + + const baseTarif = isResident ? matchingCat.tarifBase : matchingCat.tarifExterieur; + const equipContrib = parseFloat(row.getAttribute('data-equipements-contrib') || '0'); + const totalPaye = parseFloat(row.getAttribute('data-total-paye') || '0'); + const newTotal = baseTarif + equipContrib; + const newReste = Math.max(0, newTotal - totalPaye); + + const catCell = row.querySelector('.cell-tarif-categorie'); + if (catCell) { + const parentTd = catCell.parentNode; + const spanName = parentTd.querySelector('span:not(.cell-tarif-categorie)'); + if (spanName) { + spanName.textContent = matchingCat.nom; + } + catCell.textContent = baseTarif.toFixed(2) + ' € (Catégorie)'; + } + + const globalCell = row.querySelector('.cell-tarif-global'); + if (globalCell) { + globalCell.textContent = newTotal.toFixed(2) + ' €'; + } + + const resteCell = row.querySelector('.cell-reste-payer'); + if (resteCell) { + resteCell.textContent = newReste.toFixed(2) + ' €'; + if (newReste === 0) { + resteCell.classList.remove('text-red-600'); + resteCell.classList.add('text-green-600'); + } else { + resteCell.classList.remove('text-green-600'); + resteCell.classList.add('text-red-600'); + } + } + + const payerBtn = row.querySelector('.btn-payer'); + if (payerBtn) { + if (newReste > 0) { + payerBtn.classList.remove('hidden'); + const licId = payerBtn.getAttribute('data-licence-id'); + payerBtn.setAttribute('onclick', `openPaiementModal(${licId}, ${newReste})`); + } else { + payerBtn.classList.add('hidden'); + } + } + + const modifierBtn = row.querySelector('button[onclick^="openLicenceModal"]'); + if (modifierBtn) { + modifierBtn.setAttribute('data-categorie-id', matchingCat.id); + } + }); + } + + dateInput.addEventListener('change', function() { + updateRepresentantBlock(); + updateLicencesCategoryAndPrices(); + }); // Initial check in case it's a validation error reload updateRepresentantBlock(); @@ -475,7 +564,6 @@ } // Recalculate price dynamically when residentTalange checkbox changes - const residentCheckbox = document.getElementById('residentTalange'); if (residentCheckbox) { residentCheckbox.addEventListener('change', function() { const isResident = this.checked;