Files
unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/Cotisation.java

185 lines
5.5 KiB
Java

package dev.lions.unionflow.server.entity;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* Entité Cotisation avec UUID Représente une cotisation d'un membre à son organisation
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@Entity
@Table(
name = "cotisations",
indexes = {
@Index(name = "idx_cotisation_membre", columnList = "membre_id"),
@Index(name = "idx_cotisation_reference", columnList = "numero_reference", unique = true),
@Index(name = "idx_cotisation_statut", columnList = "statut"),
@Index(name = "idx_cotisation_echeance", columnList = "date_echeance"),
@Index(name = "idx_cotisation_type", columnList = "type_cotisation"),
@Index(name = "idx_cotisation_annee_mois", columnList = "annee, mois")
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class Cotisation extends BaseEntity {
@NotBlank
@Column(name = "numero_reference", unique = true, nullable = false, length = 50)
private String numeroReference;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "membre_id", nullable = false)
private Membre membre;
@NotBlank
@Column(name = "type_cotisation", nullable = false, length = 50)
private String typeCotisation;
@NotNull
@DecimalMin(value = "0.0", message = "Le montant dû doit être positif")
@Digits(integer = 10, fraction = 2)
@Column(name = "montant_du", nullable = false, precision = 12, scale = 2)
private BigDecimal montantDu;
@Builder.Default
@DecimalMin(value = "0.0", message = "Le montant payé doit être positif")
@Digits(integer = 10, fraction = 2)
@Column(name = "montant_paye", nullable = false, precision = 12, scale = 2)
private BigDecimal montantPaye = BigDecimal.ZERO;
@NotBlank
@Pattern(regexp = "^[A-Z]{3}$", message = "Le code devise doit être un code ISO à 3 lettres")
@Column(name = "code_devise", nullable = false, length = 3)
private String codeDevise;
@NotBlank
@Pattern(regexp = "^(EN_ATTENTE|PAYEE|EN_RETARD|PARTIELLEMENT_PAYEE|ANNULEE)$")
@Column(name = "statut", nullable = false, length = 30)
private String statut;
@NotNull
@Column(name = "date_echeance", nullable = false)
private LocalDate dateEcheance;
@Column(name = "date_paiement")
private LocalDateTime datePaiement;
@Size(max = 500)
@Column(name = "description", length = 500)
private String description;
@Size(max = 20)
@Column(name = "periode", length = 20)
private String periode;
@NotNull
@Min(value = 2020, message = "L'année doit être supérieure à 2020")
@Max(value = 2100, message = "L'année doit être inférieure à 2100")
@Column(name = "annee", nullable = false)
private Integer annee;
@Min(value = 1, message = "Le mois doit être entre 1 et 12")
@Max(value = 12, message = "Le mois doit être entre 1 et 12")
@Column(name = "mois")
private Integer mois;
@Size(max = 1000)
@Column(name = "observations", length = 1000)
private String observations;
@Builder.Default
@Column(name = "recurrente", nullable = false)
private Boolean recurrente = false;
@Builder.Default
@Min(value = 0, message = "Le nombre de rappels doit être positif")
@Column(name = "nombre_rappels", nullable = false)
private Integer nombreRappels = 0;
@Column(name = "date_dernier_rappel")
private LocalDateTime dateDernierRappel;
@Column(name = "valide_par_id")
private UUID valideParId;
@Size(max = 100)
@Column(name = "nom_validateur", length = 100)
private String nomValidateur;
@Column(name = "date_validation")
private LocalDateTime dateValidation;
@Size(max = 50)
@Column(name = "methode_paiement", length = 50)
private String methodePaiement;
@Size(max = 100)
@Column(name = "reference_paiement", length = 100)
private String referencePaiement;
/** Méthode métier pour calculer le montant restant à payer */
public BigDecimal getMontantRestant() {
if (montantDu == null || montantPaye == null) {
return BigDecimal.ZERO;
}
return montantDu.subtract(montantPaye);
}
/** Méthode métier pour vérifier si la cotisation est entièrement payée */
public boolean isEntierementPayee() {
return getMontantRestant().compareTo(BigDecimal.ZERO) <= 0;
}
/** Méthode métier pour vérifier si la cotisation est en retard */
public boolean isEnRetard() {
return dateEcheance != null && dateEcheance.isBefore(LocalDate.now()) && !isEntierementPayee();
}
/** Méthode métier pour générer un numéro de référence unique */
public static String genererNumeroReference() {
return "COT-"
+ LocalDate.now().getYear()
+ "-"
+ String.format("%08d", System.currentTimeMillis() % 100000000);
}
/** Callback JPA avant la persistance */
@PrePersist
protected void onCreate() {
super.onCreate(); // Appelle le onCreate de BaseEntity
if (numeroReference == null || numeroReference.isEmpty()) {
numeroReference = genererNumeroReference();
}
if (codeDevise == null) {
codeDevise = "XOF";
}
if (statut == null) {
statut = "EN_ATTENTE";
}
if (montantPaye == null) {
montantPaye = BigDecimal.ZERO;
}
if (nombreRappels == null) {
nombreRappels = 0;
}
if (recurrente == null) {
recurrente = false;
}
}
}