feat: ajout du systeme d'historique et de persistance des exports CSV

This commit is contained in:
2026-08-27 10:37:54 +02:00
parent 851fb36c2a
commit 2bc702d9bc
8 changed files with 503 additions and 0 deletions
@@ -0,0 +1,115 @@
package com.astalange.core.entity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "export_history")
public class ExportHistory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
@Column(name = "type_export", nullable = false, length = 50)
private TypeExport typeExport;
@Column(name = "nom_fichier", nullable = false)
private String nomFichier;
@Column(name = "date_export", nullable = false)
private LocalDateTime dateExport;
@Column(name = "nombre_elements")
private Integer nombreElements = 0;
@Lob
@Column(name = "contenu", nullable = false, columnDefinition = "TEXT")
private String contenu;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "saison_id")
private Saison saison;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "utilisateur_id")
private AppUser utilisateur;
public ExportHistory() {
}
public ExportHistory(TypeExport typeExport, String nomFichier, LocalDateTime dateExport, Integer nombreElements, String contenu, Saison saison, AppUser utilisateur) {
this.typeExport = typeExport;
this.nomFichier = nomFichier;
this.dateExport = dateExport;
this.nombreElements = nombreElements;
this.contenu = contenu;
this.saison = saison;
this.utilisateur = utilisateur;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public TypeExport getTypeExport() {
return typeExport;
}
public void setTypeExport(TypeExport typeExport) {
this.typeExport = typeExport;
}
public String getNomFichier() {
return nomFichier;
}
public void setNomFichier(String nomFichier) {
this.nomFichier = nomFichier;
}
public LocalDateTime getDateExport() {
return dateExport;
}
public void setDateExport(LocalDateTime dateExport) {
this.dateExport = dateExport;
}
public Integer getNombreElements() {
return nombreElements;
}
public void setNombreElements(Integer nombreElements) {
this.nombreElements = nombreElements;
}
public String getContenu() {
return contenu;
}
public void setContenu(String contenu) {
this.contenu = contenu;
}
public Saison getSaison() {
return saison;
}
public void setSaison(Saison saison) {
this.saison = saison;
}
public AppUser getUtilisateur() {
return utilisateur;
}
public void setUtilisateur(AppUser utilisateur) {
this.utilisateur = utilisateur;
}
}
@@ -0,0 +1,18 @@
package com.astalange.core.entity;
public enum TypeExport {
COMMANDE_EQUIPEMENT("Commande Équipementier (Regroupé)"),
FLOCAGE_INITIALES("Flocage Initiales"),
FLOCAGE_PRENOM_NUMERO("Flocage Prénom / N°"),
RECHERCHE_EQUIPEMENTS("Recherche Équipements");
private final String libelle;
TypeExport(String libelle) {
this.libelle = libelle;
}
public String getLibelle() {
return libelle;
}
}
@@ -0,0 +1,20 @@
package com.astalange.core.repository;
import com.astalange.core.entity.ExportHistory;
import com.astalange.core.entity.Saison;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ExportHistoryRepository extends JpaRepository<ExportHistory, Long> {
@Query("SELECT e FROM ExportHistory e LEFT JOIN FETCH e.saison LEFT JOIN FETCH e.utilisateur ORDER BY e.dateExport DESC")
List<ExportHistory> findAllWithDetails();
@Query("SELECT e FROM ExportHistory e LEFT JOIN FETCH e.saison LEFT JOIN FETCH e.utilisateur WHERE e.saison = :saison ORDER BY e.dateExport DESC")
List<ExportHistory> findBySaisonWithDetails(@Param("saison") Saison saison);
}
@@ -0,0 +1,55 @@
package com.astalange.core.service;
import com.astalange.core.entity.AppUser;
import com.astalange.core.entity.ExportHistory;
import com.astalange.core.entity.Saison;
import com.astalange.core.entity.TypeExport;
import com.astalange.core.repository.ExportHistoryRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Service
public class ExportHistoryService {
private final ExportHistoryRepository exportHistoryRepository;
public ExportHistoryService(ExportHistoryRepository exportHistoryRepository) {
this.exportHistoryRepository = exportHistoryRepository;
}
@Transactional
public ExportHistory enregistrerExport(TypeExport typeExport, String nomFichier, String csvContent, Integer nombreElements, Saison saison, AppUser utilisateur) {
ExportHistory history = new ExportHistory(
typeExport,
nomFichier,
LocalDateTime.now(),
nombreElements,
csvContent,
saison,
utilisateur
);
return exportHistoryRepository.save(history);
}
@Transactional(readOnly = true)
public List<ExportHistory> obtenirToutLHistorique() {
return exportHistoryRepository.findAllWithDetails();
}
@Transactional(readOnly = true)
public List<ExportHistory> obtenirHistoriqueParSaison(Saison saison) {
if (saison == null) {
return obtenirToutLHistorique();
}
return exportHistoryRepository.findBySaisonWithDetails(saison);
}
@Transactional(readOnly = true)
public Optional<ExportHistory> trouverParId(Long id) {
return exportHistoryRepository.findById(id);
}
}
@@ -0,0 +1,12 @@
CREATE TABLE export_history (
id BIGSERIAL PRIMARY KEY,
type_export VARCHAR(50) NOT NULL,
nom_fichier VARCHAR(255) NOT NULL,
date_export TIMESTAMP NOT NULL,
nombre_elements INT DEFAULT 0,
contenu TEXT NOT NULL,
saison_id BIGINT,
utilisateur_id BIGINT,
CONSTRAINT fk_export_history_saison FOREIGN KEY (saison_id) REFERENCES saison(id) ON DELETE SET NULL,
CONSTRAINT fk_export_history_user FOREIGN KEY (utilisateur_id) REFERENCES app_user(id) ON DELETE SET NULL
);
@@ -0,0 +1,91 @@
package com.astalange.core.service;
import com.astalange.core.entity.AppUser;
import com.astalange.core.entity.ExportHistory;
import com.astalange.core.entity.Saison;
import com.astalange.core.entity.TypeExport;
import com.astalange.core.repository.ExportHistoryRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
public class ExportHistoryServiceTest {
@Mock
private ExportHistoryRepository exportHistoryRepository;
@InjectMocks
private ExportHistoryService exportHistoryService;
private Saison saison;
private AppUser user;
@BeforeEach
public void setUp() {
saison = new Saison();
saison.setId(1L);
saison.setNom("2026-2027");
user = new AppUser();
user.setId(10L);
user.setUsername("admin");
}
@Test
@DisplayName("Enregistrer un export - doit sauvegarder les métadonnées et le contenu CSV")
public void testEnregistrerExport() {
String csv = "Header1;Header2\nValue1;Value2";
when(exportHistoryRepository.save(any(ExportHistory.class))).thenAnswer(invocation -> {
ExportHistory arg = invocation.getArgument(0);
arg.setId(100L);
return arg;
});
ExportHistory result = exportHistoryService.enregistrerExport(
TypeExport.COMMANDE_EQUIPEMENT,
"commande.csv",
csv,
1,
saison,
user
);
assertNotNull(result);
assertEquals(100L, result.getId());
assertEquals(TypeExport.COMMANDE_EQUIPEMENT, result.getTypeExport());
assertEquals("commande.csv", result.getNomFichier());
assertEquals(csv, result.getContenu());
assertEquals(1, result.getNombreElements());
assertEquals(saison, result.getSaison());
assertEquals(user, result.getUtilisateur());
verify(exportHistoryRepository, times(1)).save(any(ExportHistory.class));
}
@Test
@DisplayName("Obtenir l'historique par saison")
public void testObtenirHistoriqueParSaison() {
ExportHistory h = new ExportHistory();
h.setId(1L);
h.setTypeExport(TypeExport.FLOCAGE_INITIALES);
when(exportHistoryRepository.findBySaisonWithDetails(saison)).thenReturn(List.of(h));
List<ExportHistory> result = exportHistoryService.obtenirHistoriqueParSaison(saison);
assertEquals(1, result.size());
assertEquals(TypeExport.FLOCAGE_INITIALES, result.get(0).getTypeExport());
verify(exportHistoryRepository, times(1)).findBySaisonWithDetails(saison);
}
}