Files
unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/Paiement.java
dahoud 217021933e fix(paiement): rendre colonnes legacy nullables + refactor Paiement/PaiementObjet
Migrations :
- V25 : numero_transaction nullable dans paiements (legacy V1 NOT NULL bloquant INSERT)
- V26 : autres colonnes legacy NOT NULL V1 (type_paiement, statut_paiement, etc.)
  rendues nullables pour alignement avec l'entité Paiement

Refactor Paiement/PaiementObjet : mise à jour entités, repository, resource, service
pour cohérence avec le nouveau module Versement. Tests associés supprimés/ajustés.
2026-04-15 20:23:30 +00:00

150 lines
4.5 KiB
Java

package dev.lions.unionflow.server.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* Entité Paiement centralisée pour tous les types de paiements.
* Réutilisable pour cotisations, adhésions, événements, aides.
*
* @author UnionFlow Team
* @version 3.0
* @since 2025-01-29
*/
@Entity
@Table(name = "paiements", indexes = {
@Index(name = "idx_paiement_numero_reference", columnList = "numero_reference", unique = true),
@Index(name = "idx_paiement_membre", columnList = "membre_id"),
@Index(name = "idx_paiement_statut", columnList = "statut_paiement"),
@Index(name = "idx_paiement_methode", columnList = "methode_paiement"),
@Index(name = "idx_paiement_date", columnList = "date_paiement")
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class Paiement extends BaseEntity {
/** Numéro de référence unique */
@NotBlank
@Column(name = "numero_reference", unique = true, nullable = false, length = 50)
private String numeroReference;
/** Montant du paiement */
@NotNull
@DecimalMin(value = "0.0", message = "Le montant doit être positif")
@Digits(integer = 12, fraction = 2)
@Column(name = "montant", nullable = false, precision = 14, scale = 2)
private BigDecimal montant;
/** Code devise (ISO 3 lettres) */
@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;
/** Méthode de paiement */
@NotNull
@Column(name = "methode_paiement", nullable = false, length = 50)
private String methodePaiement;
/** Statut du paiement */
@NotNull
@Builder.Default
@Column(name = "statut_paiement", nullable = false, length = 30)
private String statutPaiement = "EN_ATTENTE";
/** Date de paiement */
@Column(name = "date_paiement")
private LocalDateTime datePaiement;
/** Date de validation */
@Column(name = "date_validation")
private LocalDateTime dateValidation;
/** Validateur (email de l'administrateur) */
@Column(name = "validateur", length = 255)
private String validateur;
/** Référence externe (numéro transaction, URL preuve, etc.) */
@Column(name = "reference_externe", length = 500)
private String referenceExterne;
/** URL de preuve de paiement */
@Column(name = "url_preuve", length = 1000)
private String urlPreuve;
/** Commentaires et notes */
@Column(name = "commentaire", length = 1000)
private String commentaire;
/** Adresse IP de l'initiateur */
@Column(name = "ip_address", length = 45)
private String ipAddress;
/** User-Agent de l'initiateur */
@Column(name = "user_agent", length = 500)
private String userAgent;
/** Membre payeur */
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "membre_id", nullable = false)
private Membre membre;
/** Objets cibles de ce paiement (polymorphique) */
@JsonIgnore
@OneToMany(mappedBy = "paiement", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Builder.Default
private List<PaiementObjet> paiementsObjets = new ArrayList<>();
/** Relation avec TransactionWave (optionnelle) */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "transaction_wave_id")
private TransactionWave transactionWave;
/** Génère un numéro de référence unique */
public static String genererNumeroReference() {
return "PAY-"
+ LocalDateTime.now().getYear()
+ "-"
+ String.format("%012d", System.currentTimeMillis() % 1000000000000L);
}
/** Vérifie si le paiement est validé */
public boolean isValide() {
return "VALIDE".equals(statutPaiement);
}
/** Vérifie si le paiement peut être modifié */
public boolean peutEtreModifie() {
return !"VALIDE".equals(statutPaiement)
&& !"ANNULE".equals(statutPaiement);
}
@PrePersist
protected void onCreate() {
super.onCreate();
if (numeroReference == null || numeroReference.isEmpty()) {
numeroReference = genererNumeroReference();
}
if (statutPaiement == null) {
statutPaiement = "EN_ATTENTE";
}
if (datePaiement == null) {
datePaiement = LocalDateTime.now();
}
}
}