feat: add category duplication functionality

This commit is contained in:
2026-07-07 21:54:38 +02:00
parent 29f9dc3bc2
commit a7c5b23198
4 changed files with 81 additions and 3 deletions
@@ -149,7 +149,18 @@ public class CategorieService {
newDotation.setTaille("");
newDotation.setNumero("");
if (licence.getAdherent() != null) {
newDotation.setFlocage(licence.getAdherent().getNom().toUpperCase() + " " + licence.getAdherent().getPrenom());
String defaultFlocage = "";
if (ce.getEquipement().isHasFlocagePrenom() && ce.getEquipement().isHasFlocageInitiales()) {
String firstInitial = licence.getAdherent().getNom() != null && !licence.getAdherent().getNom().isEmpty() ? licence.getAdherent().getNom().substring(0, 1).toUpperCase() + "." : "";
defaultFlocage = (licence.getAdherent().getPrenom() != null ? licence.getAdherent().getPrenom() + " " : "") + firstInitial;
} else if (ce.getEquipement().isHasFlocagePrenom()) {
defaultFlocage = licence.getAdherent().getPrenom() != null ? licence.getAdherent().getPrenom() : "";
} else if (ce.getEquipement().isHasFlocageInitiales()) {
String firstInitP = licence.getAdherent().getPrenom() != null && !licence.getAdherent().getPrenom().isEmpty() ? licence.getAdherent().getPrenom().substring(0, 1).toUpperCase() : "";
String firstInitN = licence.getAdherent().getNom() != null && !licence.getAdherent().getNom().isEmpty() ? licence.getAdherent().getNom().substring(0, 1).toUpperCase() : "";
defaultFlocage = firstInitP + firstInitN;
}
newDotation.setFlocage(defaultFlocage.trim());
}
currentDotations.add(newDotation);
}
@@ -157,4 +168,37 @@ public class CategorieService {
licenceRepository.save(licence);
}
@Transactional
public Categorie duplicateCategorie(Long id) {
Categorie existing = categorieRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Invalid category ID: " + id));
Categorie duplicated = new Categorie();
// Appending ' (dupliqué)' and truncating if necessary since nom is max 20 chars
String newNom = existing.getNom() + " (dupliqué)";
if (newNom.length() > 20) {
newNom = newNom.substring(0, 20);
}
duplicated.setNom(newNom);
duplicated.setSexe(existing.getSexe());
duplicated.setAnneeMin(existing.getAnneeMin());
duplicated.setAnneeMax(existing.getAnneeMax());
duplicated.setTarifBase(existing.getTarifBase());
duplicated.setTarifExterieur(existing.getTarifExterieur());
duplicated.setSaison(existing.getSaison());
List<CategorieEquipement> nouveauxEquipements = new ArrayList<>();
for (CategorieEquipement ce : existing.getCategorieEquipements()) {
CategorieEquipement newCe = new CategorieEquipement();
newCe.setCategorie(duplicated);
newCe.setEquipement(ce.getEquipement());
newCe.setObligatoire(ce.getObligatoire());
newCe.setPrix(ce.getPrix() != null ? ce.getPrix() : java.math.BigDecimal.ZERO);
nouveauxEquipements.add(newCe);
}
duplicated.getCategorieEquipements().addAll(nouveauxEquipements);
return categorieRepository.save(duplicated);
}
}
@@ -36,7 +36,9 @@ public class CategorieController {
@GetMapping("/new")
public String showCreateForm(Model model) {
if (!model.containsAttribute("categorie")) {
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";
@@ -59,7 +61,26 @@ public class CategorieController {
@PostMapping
public String saveCategorie(@ModelAttribute("categorie") Categorie categorie,
jakarta.servlet.http.HttpServletRequest request) {
jakarta.servlet.http.HttpServletRequest request,
org.springframework.web.servlet.mvc.support.RedirectAttributes redirectAttributes) {
Saison activeSaison;
if (categorie.getId() == null) {
activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
} else {
Categorie existing = categorieRepository.findById(categorie.getId()).orElse(null);
activeSaison = existing != null ? existing.getSaison() : null;
}
if (activeSaison != null) {
for (Categorie c : categorieRepository.findBySaison(activeSaison)) {
if (c.getNom().equalsIgnoreCase(categorie.getNom()) && (categorie.getId() == null || !c.getId().equals(categorie.getId()))) {
redirectAttributes.addFlashAttribute("errorMessage", "Erreur : La catégorie '" + categorie.getNom() + "' existe déjà pour cette saison.");
redirectAttributes.addFlashAttribute("categorie", categorie);
return categorie.getId() == null ? "redirect:/categories/new" : "redirect:/categories/" + categorie.getId() + "/edit";
}
}
}
java.util.Map<Long, com.astalange.core.service.CategorieService.EquipementConfig> configs = new java.util.HashMap<>();
@@ -93,4 +114,10 @@ public class CategorieController {
categorieRepository.delete(categorie);
return "redirect:/categories";
}
@PostMapping("/{id}/duplicate")
public String duplicateCategorie(@PathVariable Long id) {
categorieService.duplicateCategorie(id);
return "redirect:/categories";
}
}
@@ -22,6 +22,10 @@
<form th:action="@{/categories}" th:object="${categorie}" method="post" class="space-y-6">
<input type="hidden" th:field="*{id}" />
<div th:if="${errorMessage}" class="bg-red-50 border-l-4 border-red-500 p-4 mb-6">
<p class="text-sm text-red-700" th:text="${errorMessage}"></p>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Nom (ex: U15)</label>
@@ -56,6 +56,9 @@
<td class="py-4 px-6 text-right font-medium text-purple-600" th:text="${cat.tarifExterieur != null ? cat.tarifExterieur + ' €' : '-'}">130.00 €</td>
<td class="py-4 px-6 text-right flex justify-end space-x-3 items-center">
<a th:href="@{/categories/{id}/edit(id=${cat.id})}" class="text-indigo-600 hover:text-indigo-900 font-medium bg-indigo-50 px-3 py-1 rounded-lg">Modifier</a>
<form th:action="@{/categories/{id}/duplicate(id=${cat.id})}" method="post">
<button type="submit" class="text-green-600 hover:text-green-800 font-medium bg-green-50 px-3 py-1 rounded-lg">Dupliquer</button>
</form>
<form th:action="@{/categories/{id}/delete(id=${cat.id})}" method="post" onsubmit="return confirm('Supprimer cette catégorie ?');">
<button type="submit" class="text-red-600 hover:text-red-800 font-medium">Supprimer</button>
</form>