chore: add crypto payment

This commit is contained in:
2026-03-18 19:20:37 +01:00
parent adf68201fd
commit a00dd475f3
8 changed files with 471 additions and 254 deletions
@@ -76,6 +76,7 @@ func IPNWebhook(c *gin.Context) {
// GetCommandPaymentStatus - GET /api/v1/commands/:id/payment-status
// Retourne le statut du paiement crypto d'une commande (polling côté client)
// Effectue un refresh temps réel depuis NowPayments si le paiement est encore en attente
func GetCommandPaymentStatus(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
@@ -95,6 +96,30 @@ func GetCommandPaymentStatus(c *gin.Context) {
return
}
// Refresh temps réel depuis NowPayments pour les statuts intermédiaires (comme la référence)
switch payment.Status {
case "waiting", "confirming", "confirmed", "sending":
np, npOk := c.Get("nowpayments")
if npOk && np != nil {
npClient := np.(*services.NowPaymentsClient)
npStatus, err := npClient.GetPaymentStatus(payment.NowPaymentID)
if err == nil && npStatus.PaymentStatus != payment.Status {
payAmount, _ := npStatus.PayAmount.Float64()
if updateErr := database.UpdateCryptoPaymentStatus(payment.ID, npStatus.PaymentStatus, payAmount); updateErr == nil {
payment.Status = npStatus.PaymentStatus
payment.PayAmount = payAmount
log.Printf("[PAYMENT-STATUS] cmd %d: %s → %s (refresh temps réel)", commandID, payment.Status, npStatus.PaymentStatus)
}
switch npStatus.PaymentStatus {
case "finished", "confirmed":
_ = database.ActivateCryptoCommand(commandID)
case "failed", "expired":
_ = database.CancelCryptoCommand(commandID)
}
}
}
}
c.JSON(http.StatusOK, gin.H{
"command_id": payment.CommandID,
"payment_status": payment.Status,
+11 -9
View File
@@ -27,15 +27,17 @@ func GetPublicSettings(c *gin.Context) {
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"penalties_enabled": settings.PenaltiesEnabled,
"show_amende_score": settings.ShowAmendeScore,
"points_enabled": settings.PointsEnabled,
"points_separated": len(settings.PointsPools) > 1,
"pool_names": poolNames,
"pool_keys": poolKeys,
"referral_enabled": settings.ReferralEnabled,
"delivery_schedule": settings.DeliverySchedule,
"success": true,
"penalties_enabled": settings.PenaltiesEnabled,
"show_amende_score": settings.ShowAmendeScore,
"points_enabled": settings.PointsEnabled,
"points_separated": len(settings.PointsPools) > 1,
"pool_names": poolNames,
"pool_keys": poolKeys,
"referral_enabled": settings.ReferralEnabled,
"delivery_schedule": settings.DeliverySchedule,
"crypto_payment_enabled": settings.CryptoPaymentEnabled,
"nowpayments_currencies": settings.NowPaymentsCurrencies,
})
}
+20
View File
@@ -87,6 +87,16 @@ func main() {
// Démarrage des workers Redis en arrière-plan
go workers.StartRedisWorkers(database)
log.Println("✅ Workers Redis démarrés")
// Worker de vérification des paiements crypto (recharge les clés dynamiquement)
workers.StartDynamicPaymentChecker(database, func() *services.NowPaymentsClient {
s, err := database.GetSettings()
if err != nil || !s.CryptoPaymentEnabled || s.NowPaymentsAPIKey == "" {
return nil
}
return services.NewNowPaymentsClient(s.NowPaymentsAPIKey, s.NowPaymentsIPNSecret)
}, 2*time.Minute)
log.Println("✅ Worker paiements crypto démarré (2 min)")
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
@@ -118,6 +128,16 @@ func main() {
c.Next()
})
// Middleware NowPayments : injecte le client si crypto activé dans les settings
r.Use(func(c *gin.Context) {
settings, err := database.GetSettings()
if err == nil && settings.CryptoPaymentEnabled && settings.NowPaymentsAPIKey != "" {
np := services.NewNowPaymentsClient(settings.NowPaymentsAPIKey, settings.NowPaymentsIPNSecret)
c.Set("nowpayments", np)
}
c.Next()
})
// Fichiers statiques
r.Static("/uploads", "./uploads")
@@ -17,6 +17,23 @@ func StartPaymentChecker(database *db.Database, np *services.NowPaymentsClient,
log.Printf("[CRON] payment checker démarré (toutes les %s)", interval)
}
// StartDynamicPaymentChecker démarre un checker qui recharge le client NowPayments à chaque tick
// (permet de prendre en compte les changements de clé API sans redémarrer)
func StartDynamicPaymentChecker(database *db.Database, clientFn func() *services.NowPaymentsClient, interval time.Duration) {
go func() {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for range ticker.C {
np := clientFn()
if np == nil {
continue
}
checkPendingCryptoPayments(database, np)
}
}()
log.Printf("[CRON] payment checker dynamique démarré (toutes les %s)", interval)
}
func checkPendingCryptoPayments(database *db.Database, np *services.NowPaymentsClient) {
payments, err := database.GetPendingCryptoPayments()
if err != nil {