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 java.util.concurrent.atomic.AtomicLong; import lombok.*; /** * Versement — acte de régler une cotisation ou de déposer des fonds. * *
Un versement peut être effectué : *
Table DB : {@code paiements} (nom hérité, conservé pour compatibilité Flyway).
*
* @author UnionFlow Team
* @version 4.0
* @since 2026-04-13
*/
@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 Versement extends BaseEntity {
private static final AtomicLong REFERENCE_COUNTER =
new AtomicLong(System.currentTimeMillis() % 1_000_000_000_000L);
// ── Identité ──────────────────────────────────────────────────────────────
/** Référence unique (ex: VRS-2026-XXXXXXXXXXXX) */
@NotBlank
@Column(name = "numero_reference", unique = true, nullable = false, length = 50)
private String numeroReference;
// ── Montant ───────────────────────────────────────────────────────────────
@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;
@NotBlank
@Pattern(regexp = "^[A-Z]{3}$", message = "Code devise ISO à 3 lettres requis")
@Column(name = "code_devise", nullable = false, length = 3)
private String codeDevise;
// ── Méthode & Statut ──────────────────────────────────────────────────────
/** WAVE | ESPECES | VIREMENT | CHEQUE | AUTRE */
@NotNull
@Column(name = "methode_paiement", nullable = false, length = 50)
private String methodePaiement;
/** EN_ATTENTE | EN_COURS | CONFIRME | ECHEC | EN_ATTENTE_VALIDATION | ANNULE */
@NotNull
@Builder.Default
@Column(name = "statut_paiement", nullable = false, length = 30)
private String statutPaiement = "EN_ATTENTE";
// ── Dates ─────────────────────────────────────────────────────────────────
@Column(name = "date_paiement")
private LocalDateTime datePaiement;
@Column(name = "date_validation")
private LocalDateTime dateValidation;
// ── Validation ────────────────────────────────────────────────────────────
@Column(name = "validateur", length = 255)
private String validateur;
// ── Traçabilité ───────────────────────────────────────────────────────────
/** ID transaction Wave (TCN...) ou référence chèque / bordereau */
@Column(name = "reference_externe", length = 500)
private String referenceExterne;
@Column(name = "url_preuve", length = 1000)
private String urlPreuve;
@Column(name = "commentaire", length = 1000)
private String commentaire;
@Column(name = "ip_address", length = 45)
private String ipAddress;
@Column(name = "user_agent", length = 500)
private String userAgent;
// ── Téléphone Wave ────────────────────────────────────────────────────────
/**
* Numéro de téléphone Wave utilisé pour ce versement.
* Pré-rempli depuis le profil du membre (même téléphone qu'UnionFlow),
* modifiable à l'étape "Récapitulatif" avant de tapper "Payer".
*/
@Column(name = "numero_telephone", length = 20)
private String numeroTelephone;
// ── Relations ─────────────────────────────────────────────────────────────
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "membre_id", nullable = false)
private Membre membre;
@JsonIgnore
@OneToMany(mappedBy = "versement", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Builder.Default
private List