185 lines
5.5 KiB
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;
|
|
}
|
|
}
|
|
}
|