feat: PHASE 5.1 - Entités Gestion Documentaire
Entités créées: - Document: Gestion sécurisée avec hash MD5/SHA256, vérification intégrité - PieceJointe: Association flexible avec relations multiples Enum créé (module API): - TypeDocument: IDENTITE, JUSTIFICATIF_DOMICILE, PHOTO, CONTRAT, FACTURE, RECU, RAPPORT, AUTRE Fonctionnalités: - Vérification intégrité avec MD5 et SHA256 - Formatage taille fichiers - Compteur téléchargements - Relations flexibles: Membre, Organisation, Cotisation, Adhesion, DemandeAide, TransactionWave - Validation qu'une seule relation est renseignée Respect strict DRY/WOU: - Patterns d'entité cohérents - Enum dans module API réutilisable
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
package dev.lions.unionflow.server.entity;
|
||||
|
||||
import dev.lions.unionflow.server.api.enums.document.TypeDocument;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Entité Document pour la gestion documentaire sécurisée
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
* @since 2025-01-29
|
||||
*/
|
||||
@Entity
|
||||
@Table(
|
||||
name = "documents",
|
||||
indexes = {
|
||||
@Index(name = "idx_document_nom_fichier", columnList = "nom_fichier"),
|
||||
@Index(name = "idx_document_type", columnList = "type_document"),
|
||||
@Index(name = "idx_document_hash_md5", columnList = "hash_md5"),
|
||||
@Index(name = "idx_document_hash_sha256", columnList = "hash_sha256")
|
||||
})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Document extends BaseEntity {
|
||||
|
||||
/** Nom du fichier original */
|
||||
@NotBlank
|
||||
@Column(name = "nom_fichier", nullable = false, length = 255)
|
||||
private String nomFichier;
|
||||
|
||||
/** Nom original du fichier (tel que téléchargé) */
|
||||
@Column(name = "nom_original", length = 255)
|
||||
private String nomOriginal;
|
||||
|
||||
/** Chemin de stockage */
|
||||
@NotBlank
|
||||
@Column(name = "chemin_stockage", nullable = false, length = 1000)
|
||||
private String cheminStockage;
|
||||
|
||||
/** Type MIME */
|
||||
@Column(name = "type_mime", length = 100)
|
||||
private String typeMime;
|
||||
|
||||
/** Taille du fichier en octets */
|
||||
@NotNull
|
||||
@Min(value = 0, message = "La taille doit être positive")
|
||||
@Column(name = "taille_octets", nullable = false)
|
||||
private Long tailleOctets;
|
||||
|
||||
/** Type de document */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "type_document", length = 50)
|
||||
private TypeDocument typeDocument;
|
||||
|
||||
/** Hash MD5 pour vérification d'intégrité */
|
||||
@Column(name = "hash_md5", length = 32)
|
||||
private String hashMd5;
|
||||
|
||||
/** Hash SHA256 pour vérification d'intégrité */
|
||||
@Column(name = "hash_sha256", length = 64)
|
||||
private String hashSha256;
|
||||
|
||||
/** Description du document */
|
||||
@Column(name = "description", length = 1000)
|
||||
private String description;
|
||||
|
||||
/** Nombre de téléchargements */
|
||||
@Builder.Default
|
||||
@Column(name = "nombre_telechargements", nullable = false)
|
||||
private Integer nombreTelechargements = 0;
|
||||
|
||||
/** Date de dernier téléchargement */
|
||||
@Column(name = "date_dernier_telechargement")
|
||||
private java.time.LocalDateTime dateDernierTelechargement;
|
||||
|
||||
/** Pièces jointes associées */
|
||||
@OneToMany(mappedBy = "document", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
@Builder.Default
|
||||
private List<PieceJointe> piecesJointes = new ArrayList<>();
|
||||
|
||||
/** Méthode métier pour vérifier l'intégrité avec MD5 */
|
||||
public boolean verifierIntegriteMd5(String hashAttendu) {
|
||||
return hashMd5 != null && hashMd5.equalsIgnoreCase(hashAttendu);
|
||||
}
|
||||
|
||||
/** Méthode métier pour vérifier l'intégrité avec SHA256 */
|
||||
public boolean verifierIntegriteSha256(String hashAttendu) {
|
||||
return hashSha256 != null && hashSha256.equalsIgnoreCase(hashAttendu);
|
||||
}
|
||||
|
||||
/** Méthode métier pour obtenir la taille formatée */
|
||||
public String getTailleFormatee() {
|
||||
if (tailleOctets == null) {
|
||||
return "0 B";
|
||||
}
|
||||
if (tailleOctets < 1024) {
|
||||
return tailleOctets + " B";
|
||||
} else if (tailleOctets < 1024 * 1024) {
|
||||
return String.format("%.2f KB", tailleOctets / 1024.0);
|
||||
} else {
|
||||
return String.format("%.2f MB", tailleOctets / (1024.0 * 1024.0));
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback JPA avant la persistance */
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
super.onCreate();
|
||||
if (nombreTelechargements == null) {
|
||||
nombreTelechargements = 0;
|
||||
}
|
||||
if (typeDocument == null) {
|
||||
typeDocument = TypeDocument.AUTRE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package dev.lions.unionflow.server.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Entité PieceJointe pour l'association flexible de documents
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 3.0
|
||||
* @since 2025-01-29
|
||||
*/
|
||||
@Entity
|
||||
@Table(
|
||||
name = "pieces_jointes",
|
||||
indexes = {
|
||||
@Index(name = "idx_piece_jointe_document", columnList = "document_id"),
|
||||
@Index(name = "idx_piece_jointe_membre", columnList = "membre_id"),
|
||||
@Index(name = "idx_piece_jointe_organisation", columnList = "organisation_id"),
|
||||
@Index(name = "idx_piece_jointe_cotisation", columnList = "cotisation_id"),
|
||||
@Index(name = "idx_piece_jointe_adhesion", columnList = "adhesion_id"),
|
||||
@Index(name = "idx_piece_jointe_demande_aide", columnList = "demande_aide_id"),
|
||||
@Index(name = "idx_piece_jointe_transaction_wave", columnList = "transaction_wave_id")
|
||||
})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PieceJointe extends BaseEntity {
|
||||
|
||||
/** Ordre d'affichage */
|
||||
@NotNull
|
||||
@Min(value = 1, message = "L'ordre doit être positif")
|
||||
@Column(name = "ordre", nullable = false)
|
||||
private Integer ordre;
|
||||
|
||||
/** Libellé de la pièce jointe */
|
||||
@Column(name = "libelle", length = 200)
|
||||
private String libelle;
|
||||
|
||||
/** Commentaire */
|
||||
@Column(name = "commentaire", length = 500)
|
||||
private String commentaire;
|
||||
|
||||
/** Document associé */
|
||||
@NotNull
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "document_id", nullable = false)
|
||||
private Document document;
|
||||
|
||||
// Relations flexibles (une seule doit être renseignée)
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "membre_id")
|
||||
private Membre membre;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "organisation_id")
|
||||
private Organisation organisation;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "cotisation_id")
|
||||
private Cotisation cotisation;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "adhesion_id")
|
||||
private Adhesion adhesion;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "demande_aide_id")
|
||||
private DemandeAide demandeAide;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "transaction_wave_id")
|
||||
private TransactionWave transactionWave;
|
||||
|
||||
/** Méthode métier pour vérifier qu'une seule relation est renseignée */
|
||||
public boolean isValide() {
|
||||
int count = 0;
|
||||
if (membre != null) count++;
|
||||
if (organisation != null) count++;
|
||||
if (cotisation != null) count++;
|
||||
if (adhesion != null) count++;
|
||||
if (demandeAide != null) count++;
|
||||
if (transactionWave != null) count++;
|
||||
return count == 1; // Exactement une relation doit être renseignée
|
||||
}
|
||||
|
||||
/** Callback JPA avant la persistance */
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
super.onCreate();
|
||||
if (ordre == null) {
|
||||
ordre = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user