Some checks failed
CI/CD Pipeline / pipeline (push) Failing after 3m22s
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).
123 lines
4.3 KiB
Java
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);
|
|
}
|
|
}
|
|
}
|