feat: Export CSV des commandes équipements (Dashboard)
- Ajout de la génération de CSV des équipements choisis et non fournis pour la saison active. - Création du DotationService et ajout de la route /admin/equipements/export-commande. - Ajout du bouton d'export sur le tableau de bord principal (index.html).
This commit is contained in:
@@ -4,6 +4,10 @@ import com.astalange.core.entity.Dotation;
|
|||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.astalange.core.entity.Saison;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface DotationRepository extends JpaRepository<Dotation, Long> {
|
public interface DotationRepository extends JpaRepository<Dotation, Long> {
|
||||||
|
List<Dotation> findByLicence_SaisonAndChoisiTrueAndFourniFalse(Saison saison);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.astalange.core.service;
|
||||||
|
|
||||||
|
import com.astalange.core.entity.Dotation;
|
||||||
|
import com.astalange.core.entity.Saison;
|
||||||
|
import com.astalange.core.repository.DotationRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DotationService {
|
||||||
|
|
||||||
|
private final DotationRepository dotationRepository;
|
||||||
|
|
||||||
|
public DotationService(DotationRepository dotationRepository) {
|
||||||
|
this.dotationRepository = dotationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String genererCsvCommandeEquipement(Saison saisonActive) {
|
||||||
|
List<Dotation> dotations = dotationRepository.findByLicence_SaisonAndChoisiTrueAndFourniFalse(saisonActive);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
// BOM for Excel to open UTF-8 correctly
|
||||||
|
sb.append('\ufeff');
|
||||||
|
|
||||||
|
// Header
|
||||||
|
sb.append("Catégorie;Nom;Prénom;Équipement;Taille;Flocage;Numéro\n");
|
||||||
|
|
||||||
|
for (Dotation d : dotations) {
|
||||||
|
String categorie = d.getLicence().getCategorie() != null ? d.getLicence().getCategorie().getNom() : "";
|
||||||
|
String nom = d.getLicence().getAdherent().getNom();
|
||||||
|
String prenom = d.getLicence().getAdherent().getPrenom();
|
||||||
|
String equipement = d.getEquipement() != null ? d.getEquipement().getNom() : "";
|
||||||
|
String taille = d.getTaille() != null ? d.getTaille() : "";
|
||||||
|
String flocage = d.getFlocage() != null ? d.getFlocage() : "";
|
||||||
|
String numero = d.getNumero() != null ? d.getNumero() : "";
|
||||||
|
|
||||||
|
sb.append(escapeCsv(categorie)).append(";")
|
||||||
|
.append(escapeCsv(nom)).append(";")
|
||||||
|
.append(escapeCsv(prenom)).append(";")
|
||||||
|
.append(escapeCsv(equipement)).append(";")
|
||||||
|
.append(escapeCsv(taille)).append(";")
|
||||||
|
.append(escapeCsv(flocage)).append(";")
|
||||||
|
.append(escapeCsv(numero)).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String escapeCsv(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String result = value;
|
||||||
|
if (result.contains("\"")) {
|
||||||
|
result = result.replace("\"", "\"\"");
|
||||||
|
}
|
||||||
|
if (result.contains(";") || result.contains("\n") || result.contains("\"")) {
|
||||||
|
return "\"" + result + "\"";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,13 +11,42 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import com.astalange.core.service.DotationService;
|
||||||
|
import com.astalange.core.repository.SaisonRepository;
|
||||||
|
import com.astalange.core.entity.Saison;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class DotationController {
|
public class DotationController {
|
||||||
|
|
||||||
private final DotationRepository dotationRepository;
|
private final DotationRepository dotationRepository;
|
||||||
|
private final DotationService dotationService;
|
||||||
|
private final SaisonRepository saisonRepository;
|
||||||
|
|
||||||
public DotationController(DotationRepository dotationRepository) {
|
public DotationController(DotationRepository dotationRepository, DotationService dotationService, SaisonRepository saisonRepository) {
|
||||||
this.dotationRepository = dotationRepository;
|
this.dotationRepository = dotationRepository;
|
||||||
|
this.dotationService = dotationService;
|
||||||
|
this.saisonRepository = saisonRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/admin/equipements/export-commande")
|
||||||
|
public ResponseEntity<byte[]> exportCommande() {
|
||||||
|
Saison saisonActive = saisonRepository.findByEstActiveTrue()
|
||||||
|
.orElseThrow(() -> new IllegalStateException("Aucune saison active"));
|
||||||
|
|
||||||
|
String csvContent = dotationService.genererCsvCommandeEquipement(saisonActive);
|
||||||
|
byte[] csvBytes = csvContent.getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentDispositionFormData("attachment", "commande_equipements_" + LocalDate.now() + ".csv");
|
||||||
|
headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8"));
|
||||||
|
|
||||||
|
return new ResponseEntity<>(csvBytes, headers, org.springframework.http.HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/dotations/{id}")
|
@PostMapping("/dotations/{id}")
|
||||||
|
|||||||
@@ -18,8 +18,12 @@
|
|||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<main class="flex-1 flex flex-col h-screen overflow-hidden">
|
<main class="flex-1 flex flex-col h-screen overflow-hidden">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="h-16 bg-white border-b border-gray-200 flex items-center px-6">
|
<header class="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6">
|
||||||
<h2 class="text-lg font-semibold text-gray-800">Tableau de bord</h2>
|
<h2 class="text-lg font-semibold text-gray-800">Tableau de bord</h2>
|
||||||
|
<a href="/admin/equipements/export-commande" class="bg-indigo-50 text-indigo-600 border border-indigo-200 px-4 py-2 rounded-lg text-sm font-medium hover:bg-indigo-100 transition-colors flex items-center">
|
||||||
|
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
|
||||||
|
Export CSV Équipements
|
||||||
|
</a>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Main section -->
|
<!-- Main section -->
|
||||||
|
|||||||
@@ -23,8 +23,6 @@
|
|||||||
+ Nouvel Équipement
|
+ Nouvel Équipement
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
|
||||||
<table class="w-full text-left border-collapse">
|
<table class="w-full text-left border-collapse">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="bg-gray-50 text-gray-500 text-sm uppercase tracking-wider border-b border-gray-200">
|
<tr class="bg-gray-50 text-gray-500 text-sm uppercase tracking-wider border-b border-gray-200">
|
||||||
|
|||||||
Reference in New Issue
Block a user