Payment Flow + Access Flow Change
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
|
||||
)
|
||||
|
||||
type ScheduleStatus int
|
||||
|
||||
const (
|
||||
SCHEDULE_ACTIVE ScheduleStatus = iota
|
||||
SCHEDULE_PAUSED // mis en pause manuellement
|
||||
SCHEDULE_CANCELLED // résilié
|
||||
SCHEDULE_COMPLETED // terminé normalement (abonnement expiré)
|
||||
SCHEDULE_FAILED // trop d'échecs consécutifs
|
||||
)
|
||||
|
||||
func (s ScheduleStatus) String() string {
|
||||
return [...]string{"active", "paused", "cancelled", "completed", "failed"}[s]
|
||||
}
|
||||
|
||||
// PaymentSchedule pilote la récurrence des paiements d'un abonnement.
|
||||
type PaymentSchedule struct {
|
||||
SubscriptionID string `json:"subscription_id" bson:"subscription_id"`
|
||||
Frequency pricing.PaymentType `json:"frequency" bson:"frequency"` // PAY_EVERY_WEEK / PAY_EVERY_MONTH / PAY_EVERY_YEAR
|
||||
Amount float64 `json:"amount" bson:"amount"`
|
||||
Currency string `json:"currency" bson:"currency"`
|
||||
Status ScheduleStatus `json:"status" bson:"status"`
|
||||
NextPaymentDate time.Time `json:"next_payment_date" bson:"next_payment_date"`
|
||||
LastExecutedAt *time.Time `json:"last_executed_at,omitempty" bson:"last_executed_at,omitempty"`
|
||||
FailureCount int `json:"failure_count" bson:"failure_count"`
|
||||
MaxRetries int `json:"max_retries" bson:"max_retries" default:"3"`
|
||||
}
|
||||
|
||||
// nextDate calcule la prochaine date selon la fréquence.
|
||||
func (ps *PaymentSchedule) nextDate() time.Time {
|
||||
switch ps.Frequency {
|
||||
case pricing.PAY_EVERY_WEEK:
|
||||
return ps.NextPaymentDate.AddDate(0, 0, 7)
|
||||
case pricing.PAY_EVERY_MONTH:
|
||||
return ps.NextPaymentDate.AddDate(0, 1, 0)
|
||||
case pricing.PAY_EVERY_YEAR:
|
||||
return ps.NextPaymentDate.AddDate(1, 0, 0)
|
||||
}
|
||||
return ps.NextPaymentDate
|
||||
}
|
||||
|
||||
// Advance enregistre l'exécution réussie et avance à la prochaine échéance.
|
||||
func (ps *PaymentSchedule) Advance() {
|
||||
now := time.Now().UTC()
|
||||
ps.LastExecutedAt = &now
|
||||
ps.FailureCount = 0
|
||||
ps.NextPaymentDate = ps.nextDate()
|
||||
}
|
||||
|
||||
// RecordFailure incrémente le compteur d'échecs et désactive après MaxRetries.
|
||||
func (ps *PaymentSchedule) RecordFailure() {
|
||||
ps.FailureCount++
|
||||
if ps.MaxRetries > 0 && ps.FailureCount >= ps.MaxRetries {
|
||||
ps.Status = SCHEDULE_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
// IsDue retourne vrai si le paiement est dû maintenant.
|
||||
func (ps *PaymentSchedule) IsDue() bool {
|
||||
return ps.Status == SCHEDULE_ACTIVE && !time.Now().UTC().Before(ps.NextPaymentDate)
|
||||
}
|
||||
|
||||
// Pause suspend temporairement le calendrier.
|
||||
func (ps *PaymentSchedule) Pause() {
|
||||
if ps.Status == SCHEDULE_ACTIVE {
|
||||
ps.Status = SCHEDULE_PAUSED
|
||||
}
|
||||
}
|
||||
|
||||
// Resume réactive un calendrier mis en pause.
|
||||
func (ps *PaymentSchedule) Resume() {
|
||||
if ps.Status == SCHEDULE_PAUSED {
|
||||
ps.Status = SCHEDULE_ACTIVE
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user