Files
unionflow-server-impl-quarkus/src/main/java/dev/lions/unionflow/server/entity/IntentionPaiement.java
lionsdev 6e9841b3bb
Some checks failed
CI/CD Pipeline / pipeline (push) Failing after 3m22s
fix(disaster-recovery 2/2): restaurer 242 fichiers Java modifiés par a72ab54
Suite à la récupération précédente (044ca4b) qui n'avait restauré que les
fichiers SUPPRIMÉS, ce commit restaure les MODIFICATIONS d'entités/services
qui étaient nécessaires pour que les fichiers restaurés compilent.

Restaurés depuis a72ab54^ (= 31330d9 + corrections) :
- Entities : Organisation, FormuleAbonnement, AuditService, MembreOrganisation, SouscriptionOrganisation, etc.
- Services : MigrerOrganisationsVersKeycloakService, ComptabilitePdfService, KycAmlService, AuditService.logKycRisqueEleve, etc.
- Resources : PaiementUnifieResource, etc.

Backend compile désormais (BUILD SUCCESS).
2026-04-25 01:05:08 +00:00

123 lines
4.3 KiB
Java

package dev.lions.unionflow.server.entity;
import dev.lions.unionflow.server.api.enums.paiement.StatutIntentionPaiement;
import dev.lions.unionflow.server.api.enums.paiement.TypeObjetIntentionPaiement;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.*;
/**
* Hub centralisé pour tout paiement Wave initié depuis UnionFlow.
*
* <p>Flux :
* <ol>
* <li>UnionFlow crée une {@code IntentionPaiement} avec les objets cibles (cotisations, etc.)</li>
* <li>UnionFlow appelle l'API Wave → récupère {@code waveCheckoutSessionId}</li>
* <li>Le membre confirme dans l'app Wave</li>
* <li>Wave envoie un webhook → UnionFlow réconcilie via {@code waveCheckoutSessionId}</li>
* <li>UnionFlow valide automatiquement les objets listés dans {@code objetsCibles}</li>
* </ol>
*
* <p>Table : {@code intentions_paiement}
*/
@Entity
@Table(
name = "intentions_paiement",
indexes = {
@Index(name = "idx_intention_utilisateur", columnList = "utilisateur_id"),
@Index(name = "idx_intention_statut", columnList = "statut"),
@Index(name = "idx_intention_wave_session", columnList = "wave_checkout_session_id", unique = true),
@Index(name = "idx_intention_expiration", columnList = "date_expiration")
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class IntentionPaiement extends BaseEntity {
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "utilisateur_id", nullable = false)
private Membre utilisateur;
/** NULL pour les abonnements UnionFlow SA (payés par l'organisation directement) */
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "organisation_id")
private Organisation organisation;
@NotNull
@DecimalMin("0.01")
@Digits(integer = 12, fraction = 2)
@Column(name = "montant_total", nullable = false, precision = 14, scale = 2)
private BigDecimal montantTotal;
@NotBlank
@Pattern(regexp = "^[A-Z]{3}$")
@Builder.Default
@Column(name = "code_devise", nullable = false, length = 3)
private String codeDevise = "XOF";
@Enumerated(EnumType.STRING)
@NotNull
@Column(name = "type_objet", nullable = false, length = 30)
private TypeObjetIntentionPaiement typeObjet;
@Enumerated(EnumType.STRING)
@Builder.Default
@Column(name = "statut", nullable = false, length = 20)
private StatutIntentionPaiement statut = StatutIntentionPaiement.INITIEE;
/** ID de session Wave — clé de réconciliation sur webhook */
@Column(name = "wave_checkout_session_id", unique = true, length = 255)
private String waveCheckoutSessionId;
/** URL de paiement Wave à rediriger l'utilisateur */
@Column(name = "wave_launch_url", length = 1000)
private String waveLaunchUrl;
/** ID transaction Wave reçu via webhook */
@Column(name = "wave_transaction_id", length = 100)
private String waveTransactionId;
/**
* JSON : liste des objets couverts par ce paiement.
* Exemple : [{\"type\":\"COTISATION\",\"id\":\"uuid\",\"montant\":5000}, ...]
*/
@Column(name = "objets_cibles", columnDefinition = "TEXT")
private String objetsCibles;
@Column(name = "date_expiration")
private LocalDateTime dateExpiration;
@Column(name = "date_completion")
private LocalDateTime dateCompletion;
// ── Méthodes métier ────────────────────────────────────────────────────────
public boolean isActive() {
return StatutIntentionPaiement.INITIEE.equals(statut)
|| StatutIntentionPaiement.EN_COURS.equals(statut);
}
public boolean isExpiree() {
return dateExpiration != null && LocalDateTime.now().isAfter(dateExpiration);
}
public boolean isCompletee() {
return StatutIntentionPaiement.COMPLETEE.equals(statut);
}
@PrePersist
protected void onCreate() {
super.onCreate();
if (statut == null) statut = StatutIntentionPaiement.INITIEE;
if (codeDevise == null) codeDevise = "XOF";
if (dateExpiration == null) {
dateExpiration = LocalDateTime.now().plusMinutes(30);
}
}
}