Files
projet_gestion_commande/backend/gestion/handlers/crypto_payment.go
T
Xor290 5cd8ada828
Backend - Build & Lint / build (push) Failing after 31m35s
chore: build
2026-07-06 21:22:30 +02:00

132 lines
4.3 KiB
Go

package handlers
import (
"encoding/json"
"gestion/db"
"gestion/services"
"io"
"log"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
)
// IPNWebhook - POST /api/v1/webhooks/nowpayments
func IPNWebhook(c *gin.Context) {
database := c.MustGet("database").(*db.Database)
npRaw, npExists := c.Get("nowpayments")
np, ok := npRaw.(*services.NowPaymentsClient)
if !npExists || !ok || np == nil {
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "paiement crypto non configuré"})
return
}
body, err := io.ReadAll(c.Request.Body)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "impossible de lire le corps"})
return
}
sig := c.GetHeader("x-nowpayments-sig")
if !np.VerifyIPN(body, sig) {
log.Printf("[IPN] signature invalide")
c.JSON(http.StatusUnauthorized, gin.H{"error": "signature invalide"})
return
}
var payload services.IPNPayload
if err := json.Unmarshal(body, &payload); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "payload invalide"})
return
}
payment, err := database.GetCryptoPaymentByNowPaymentID(payload.PaymentID.String())
if err != nil || payment == nil {
log.Printf("[IPN] paiement introuvable: %s", payload.PaymentID.String())
c.JSON(http.StatusOK, gin.H{"ok": true})
return
}
payAmount, _ := payload.PayAmount.Float64()
if err := database.UpdateCryptoPaymentStatus(payment.ID, payload.PaymentStatus, payAmount); err != nil {
log.Printf("[IPN] erreur mise à jour paiement %d: %v", payment.ID, err)
c.JSON(http.StatusBadRequest, gin.H{"error": "erreur base de données"})
return
}
switch payload.PaymentStatus {
case "finished", "confirmed":
if err := database.ActivateCryptoCommand(payment.CommandID); err != nil {
log.Printf("[IPN] erreur activation commande %d: %v", payment.CommandID, err)
} else {
log.Printf("[IPN] commande %d activée (paiement %s confirmé)", payment.CommandID, payload.PaymentID.String())
}
case "failed", "expired":
if err := database.CancelCryptoCommand(payment.CommandID); err != nil {
log.Printf("[IPN] erreur annulation commande %d: %v", payment.CommandID, err)
} else {
log.Printf("[IPN] commande %d annulée (paiement %s)", payment.CommandID, payload.PaymentStatus)
}
}
c.JSON(http.StatusOK, gin.H{"ok": true})
}
// 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)
commandID, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "id de commande invalide"})
return
}
payment, err := database.GetCryptoPaymentByCommandID(commandID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur base de données"})
return
}
if payment == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "aucun paiement crypto pour cette commande"})
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,
"pay_address": payment.PayAddress,
"pay_amount": payment.PayAmount,
"pay_currency": payment.PayCurrency,
"price_amount": payment.PriceAmount,
"price_currency": payment.PriceCurrency,
})
}