feat: PHASE 5 COMPLÈTE - Gestion Documentaire

Service créé:
- DocumentService: CRUD documents, enregistrement téléchargements, gestion pièces jointes
- Validation qu'une seule relation est renseignée pour pièce jointe
- Conversions DTO ↔ Entity complètes

PHASE 5 - COMPLÉTÉE (100%):
 Entités: Document, PieceJointe
 Enum: TypeDocument (module API)
 Repositories: DocumentRepository, PieceJointeRepository
 DTOs: DocumentDTO, PieceJointeDTO
 Service: DocumentService avec validation
 Relations flexibles: Membre, Organisation, Cotisation, Adhesion, DemandeAide, TransactionWave

Fonctionnalités:
- Vérification intégrité avec MD5/SHA256
- Formatage taille fichiers
- Compteur téléchargements
- Validation relations pièces jointes

Respect strict DRY/WOU:
- Patterns cohérents avec autres modules
- Gestion d'erreurs standardisée
This commit is contained in:
dahoud
2025-11-30 11:31:51 +00:00
parent bf994ccbea
commit 0f625e5d78

View File

@@ -0,0 +1,311 @@
package dev.lions.unionflow.server.service;
import dev.lions.unionflow.server.api.dto.document.DocumentDTO;
import dev.lions.unionflow.server.api.dto.document.PieceJointeDTO;
import dev.lions.unionflow.server.entity.*;
import dev.lions.unionflow.server.repository.*;
import dev.lions.unionflow.server.service.KeycloakService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;
/**
* Service métier pour la gestion documentaire
*
* @author UnionFlow Team
* @version 3.0
* @since 2025-01-29
*/
@ApplicationScoped
public class DocumentService {
private static final Logger LOG = Logger.getLogger(DocumentService.class);
@Inject DocumentRepository documentRepository;
@Inject PieceJointeRepository pieceJointeRepository;
@Inject MembreRepository membreRepository;
@Inject OrganisationRepository organisationRepository;
@Inject CotisationRepository cotisationRepository;
@Inject AdhesionRepository adhesionRepository;
@Inject DemandeAideRepository demandeAideRepository;
@Inject TransactionWaveRepository transactionWaveRepository;
@Inject KeycloakService keycloakService;
/**
* Crée un nouveau document
*
* @param documentDTO DTO du document à créer
* @return DTO du document créé
*/
@Transactional
public DocumentDTO creerDocument(DocumentDTO documentDTO) {
LOG.infof("Création d'un nouveau document: %s", documentDTO.getNomFichier());
Document document = convertToEntity(documentDTO);
document.setCreePar(keycloakService.getCurrentUserEmail());
documentRepository.persist(document);
LOG.infof("Document créé avec succès: ID=%s, Fichier=%s", document.getId(), document.getNomFichier());
return convertToDTO(document);
}
/**
* Trouve un document par son ID
*
* @param id ID du document
* @return DTO du document
*/
public DocumentDTO trouverParId(UUID id) {
return documentRepository
.findByIdOptional(id)
.map(this::convertToDTO)
.orElseThrow(() -> new NotFoundException("Document non trouvé avec l'ID: " + id));
}
/**
* Enregistre un téléchargement de document
*
* @param id ID du document
*/
@Transactional
public void enregistrerTelechargement(UUID id) {
Document document =
documentRepository
.findByIdOptional(id)
.orElseThrow(() -> new NotFoundException("Document non trouvé avec l'ID: " + id));
document.setNombreTelechargements(
(document.getNombreTelechargements() != null ? document.getNombreTelechargements() : 0) + 1);
document.setDateDernierTelechargement(LocalDateTime.now());
document.setModifiePar(keycloakService.getCurrentUserEmail());
documentRepository.persist(document);
}
/**
* Crée une pièce jointe
*
* @param pieceJointeDTO DTO de la pièce jointe à créer
* @return DTO de la pièce jointe créée
*/
@Transactional
public PieceJointeDTO creerPieceJointe(PieceJointeDTO pieceJointeDTO) {
LOG.infof("Création d'une nouvelle pièce jointe");
PieceJointe pieceJointe = convertToEntity(pieceJointeDTO);
// Vérifier qu'une seule relation est renseignée
if (!pieceJointe.isValide()) {
throw new IllegalArgumentException("Une seule relation doit être renseignée pour une pièce jointe");
}
pieceJointe.setCreePar(keycloakService.getCurrentUserEmail());
pieceJointeRepository.persist(pieceJointe);
LOG.infof("Pièce jointe créée avec succès: ID=%s", pieceJointe.getId());
return convertToDTO(pieceJointe);
}
/**
* Liste toutes les pièces jointes d'un document
*
* @param documentId ID du document
* @return Liste des pièces jointes
*/
public List<PieceJointeDTO> listerPiecesJointesParDocument(UUID documentId) {
return pieceJointeRepository.findByDocumentId(documentId).stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
// ========================================
// MÉTHODES PRIVÉES
// ========================================
/** Convertit une entité Document en DTO */
private DocumentDTO convertToDTO(Document document) {
if (document == null) {
return null;
}
DocumentDTO dto = new DocumentDTO();
dto.setId(document.getId());
dto.setNomFichier(document.getNomFichier());
dto.setNomOriginal(document.getNomOriginal());
dto.setCheminStockage(document.getCheminStockage());
dto.setTypeMime(document.getTypeMime());
dto.setTailleOctets(document.getTailleOctets());
dto.setTypeDocument(document.getTypeDocument());
dto.setHashMd5(document.getHashMd5());
dto.setHashSha256(document.getHashSha256());
dto.setDescription(document.getDescription());
dto.setNombreTelechargements(document.getNombreTelechargements());
dto.setTailleFormatee(document.getTailleFormatee());
dto.setDateCreation(document.getDateCreation());
dto.setDateModification(document.getDateModification());
dto.setActif(document.getActif());
return dto;
}
/** Convertit un DTO en entité Document */
private Document convertToEntity(DocumentDTO dto) {
if (dto == null) {
return null;
}
Document document = new Document();
document.setNomFichier(dto.getNomFichier());
document.setNomOriginal(dto.getNomOriginal());
document.setCheminStockage(dto.getCheminStockage());
document.setTypeMime(dto.getTypeMime());
document.setTailleOctets(dto.getTailleOctets());
document.setTypeDocument(dto.getTypeDocument() != null ? dto.getTypeDocument() : dev.lions.unionflow.server.api.enums.document.TypeDocument.AUTRE);
document.setHashMd5(dto.getHashMd5());
document.setHashSha256(dto.getHashSha256());
document.setDescription(dto.getDescription());
document.setNombreTelechargements(dto.getNombreTelechargements() != null ? dto.getNombreTelechargements() : 0);
return document;
}
/** Convertit une entité PieceJointe en DTO */
private PieceJointeDTO convertToDTO(PieceJointe pieceJointe) {
if (pieceJointe == null) {
return null;
}
PieceJointeDTO dto = new PieceJointeDTO();
dto.setId(pieceJointe.getId());
dto.setOrdre(pieceJointe.getOrdre());
dto.setLibelle(pieceJointe.getLibelle());
dto.setCommentaire(pieceJointe.getCommentaire());
if (pieceJointe.getDocument() != null) {
dto.setDocumentId(pieceJointe.getDocument().getId());
}
if (pieceJointe.getMembre() != null) {
dto.setMembreId(pieceJointe.getMembre().getId());
}
if (pieceJointe.getOrganisation() != null) {
dto.setOrganisationId(pieceJointe.getOrganisation().getId());
}
if (pieceJointe.getCotisation() != null) {
dto.setCotisationId(pieceJointe.getCotisation().getId());
}
if (pieceJointe.getAdhesion() != null) {
dto.setAdhesionId(pieceJointe.getAdhesion().getId());
}
if (pieceJointe.getDemandeAide() != null) {
dto.setDemandeAideId(pieceJointe.getDemandeAide().getId());
}
if (pieceJointe.getTransactionWave() != null) {
dto.setTransactionWaveId(pieceJointe.getTransactionWave().getId());
}
dto.setDateCreation(pieceJointe.getDateCreation());
dto.setDateModification(pieceJointe.getDateModification());
dto.setActif(pieceJointe.getActif());
return dto;
}
/** Convertit un DTO en entité PieceJointe */
private PieceJointe convertToEntity(PieceJointeDTO dto) {
if (dto == null) {
return null;
}
PieceJointe pieceJointe = new PieceJointe();
pieceJointe.setOrdre(dto.getOrdre() != null ? dto.getOrdre() : 1);
pieceJointe.setLibelle(dto.getLibelle());
pieceJointe.setCommentaire(dto.getCommentaire());
// Relation Document
if (dto.getDocumentId() != null) {
Document document =
documentRepository
.findByIdOptional(dto.getDocumentId())
.orElseThrow(() -> new NotFoundException("Document non trouvé avec l'ID: " + dto.getDocumentId()));
pieceJointe.setDocument(document);
}
// Relations flexibles (une seule doit être renseignée)
if (dto.getMembreId() != null) {
Membre membre =
membreRepository
.findByIdOptional(dto.getMembreId())
.orElseThrow(() -> new NotFoundException("Membre non trouvé avec l'ID: " + dto.getMembreId()));
pieceJointe.setMembre(membre);
}
if (dto.getOrganisationId() != null) {
Organisation org =
organisationRepository
.findByIdOptional(dto.getOrganisationId())
.orElseThrow(
() ->
new NotFoundException(
"Organisation non trouvée avec l'ID: " + dto.getOrganisationId()));
pieceJointe.setOrganisation(org);
}
if (dto.getCotisationId() != null) {
Cotisation cotisation =
cotisationRepository
.findByIdOptional(dto.getCotisationId())
.orElseThrow(
() -> new NotFoundException("Cotisation non trouvée avec l'ID: " + dto.getCotisationId()));
pieceJointe.setCotisation(cotisation);
}
if (dto.getAdhesionId() != null) {
Adhesion adhesion =
adhesionRepository
.findByIdOptional(dto.getAdhesionId())
.orElseThrow(
() -> new NotFoundException("Adhésion non trouvée avec l'ID: " + dto.getAdhesionId()));
pieceJointe.setAdhesion(adhesion);
}
if (dto.getDemandeAideId() != null) {
DemandeAide demandeAide =
demandeAideRepository
.findByIdOptional(dto.getDemandeAideId())
.orElseThrow(
() ->
new NotFoundException(
"Demande d'aide non trouvée avec l'ID: " + dto.getDemandeAideId()));
pieceJointe.setDemandeAide(demandeAide);
}
if (dto.getTransactionWaveId() != null) {
TransactionWave transactionWave =
transactionWaveRepository
.findByIdOptional(dto.getTransactionWaveId())
.orElseThrow(
() ->
new NotFoundException(
"Transaction Wave non trouvée avec l'ID: " + dto.getTransactionWaveId()));
pieceJointe.setTransactionWave(transactionWave);
}
return pieceJointe;
}
}