mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 19:12:54 +00:00
- Add PaymentController struct with paymentService/db dependencies and NewPaymentController constructor - Add SetupRoutes with /payments endpoints (POST /top-up, POST/DELETE/GET /payment-methods, GET /transactions/:id, POST /transactions/:id/refund) and /webhooks/stripe endpoint - Add ProcessTopUp handler with amount/paymentMethodId validation, subscriberID authentication, and PaymentService.
95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package payment
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/nutcas3/telecom-platform/apps/api-server/internal/database"
|
|
)
|
|
|
|
// WebhookEvent represents a payment webhook event
|
|
type WebhookEvent struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Object string `json:"object"`
|
|
Created int64 `json:"created"`
|
|
Livemode bool `json:"livemode"`
|
|
Data map[string]any `json:"data"`
|
|
}
|
|
|
|
// WebhookHandler handles payment webhooks
|
|
type WebhookHandler struct {
|
|
paymentService *PaymentService
|
|
db *database.Database
|
|
}
|
|
|
|
// NewWebhookHandler creates a new webhook handler
|
|
func NewWebhookHandler(paymentService *PaymentService, db *database.Database) *WebhookHandler {
|
|
return &WebhookHandler{
|
|
paymentService: paymentService,
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// HandleStripeWebhook handles Stripe webhooks
|
|
func (wh *WebhookHandler) HandleStripeWebhook(c *gin.Context) {
|
|
body, err := c.GetRawData()
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to read request body"})
|
|
return
|
|
}
|
|
|
|
signature := c.GetHeader("Stripe-Signature")
|
|
if signature == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Missing signature"})
|
|
return
|
|
}
|
|
|
|
// Validate webhook
|
|
valid, err := wh.paymentService.ValidateWebhook(c.Request.Context(), signature, body)
|
|
if err != nil {
|
|
log.Printf("Webhook validation error: %v", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid webhook"})
|
|
return
|
|
}
|
|
|
|
if !valid {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid signature"})
|
|
return
|
|
}
|
|
|
|
// Parse event
|
|
var event WebhookEvent
|
|
if err := json.Unmarshal(body, &event); err != nil {
|
|
log.Printf("Failed to parse webhook event: %v", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid event format"})
|
|
return
|
|
}
|
|
|
|
// Handle different event types
|
|
switch event.Type {
|
|
case "payment_intent.succeeded":
|
|
err = wh.handlePaymentSucceeded(c.Request.Context(), event)
|
|
case "payment_intent.payment_failed":
|
|
err = wh.handlePaymentFailed(c.Request.Context(), event)
|
|
case "payment_intent.canceled":
|
|
err = wh.handlePaymentCanceled(c.Request.Context(), event)
|
|
case "charge.dispute.created":
|
|
err = wh.handleDisputeCreated(c.Request.Context(), event)
|
|
default:
|
|
log.Printf("Unhandled webhook event type: %s", event.Type)
|
|
}
|
|
|
|
if err != nil {
|
|
log.Printf("Error handling webhook event %s: %v", event.Type, err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to process webhook"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"status": "received"})
|
|
}
|
|
|