forked from Nixius/authelia
1
0
Fork 0
ATLAS/docker/ss-atlas/internal/handlers/webhook_invoice.go

97 lines
2.8 KiB
Go

package handlers
import (
"encoding/json"
"log"
"time"
stripego "github.com/stripe/stripe-go/v84"
"github.com/stripe/stripe-go/v84/subscription"
)
const freeTierMonths = 3
// maybeScheduleFreeTierCancel fetches the subscription and, if it uses the free-tier
// price, sets cancel_at to 3 months from now so it auto-cancels at end of term.
func (a *App) maybeScheduleFreeTierCancel(subID string) {
sub, err := a.stripe.GetSubscription(subID)
if err != nil {
log.Printf("webhook: could not fetch subscription %s: %v", subID, err)
return
}
if sub.Items == nil || len(sub.Items.Data) == 0 {
return
}
priceID := sub.Items.Data[0].Price.ID
if !a.stripe.IsFreeTierPrice(priceID) {
return
}
cancelAt := time.Now().AddDate(0, freeTierMonths, 0).Unix()
if err := a.stripe.ScheduleSubscriptionCancelAt(subID, cancelAt); err != nil {
log.Printf("webhook: failed to schedule free-tier cancel for sub %s: %v", subID, err)
return
}
log.Printf("webhook: scheduled free-tier sub %s to cancel at %d (3 months)", subID, cancelAt)
}
type invoicePaidPayload struct {
BillingReason stripego.InvoiceBillingReason `json:"billing_reason"`
Subscription interface{} `json:"subscription"`
Lines struct {
Data []struct {
Price struct {
ID string `json:"id"`
} `json:"price"`
} `json:"data"`
} `json:"lines"`
}
func (a *App) onInvoicePaid(event stripego.Event) {
var raw invoicePaidPayload
if err := json.Unmarshal(event.Data.Raw, &raw); err != nil {
log.Printf("invoice unmarshal error: %v", err)
return
}
if raw.BillingReason != stripego.InvoiceBillingReasonSubscriptionCycle {
return
}
subID := ""
switch v := raw.Subscription.(type) {
case string:
subID = v
case map[string]interface{}:
if id, ok := v["id"].(string); ok {
subID = id
}
}
if subID == "" || len(raw.Lines.Data) == 0 {
return
}
priceID := raw.Lines.Data[0].Price.ID
if priceID == "" || !a.stripe.IsYearTierPrice(priceID) {
return
}
price100 := a.cfg.StripePriceIDMonth100
if price100 == "" {
log.Printf("webhook: STRIPE_PRICE_ID_MONTH_100 not set, cannot migrate sub %s", subID)
return
}
sub, err := a.stripe.GetSubscription(subID)
if err != nil || sub.Items == nil || len(sub.Items.Data) == 0 {
log.Printf("webhook: could not get subscription %s for migration: %v", subID, err)
return
}
subItemID := sub.Items.Data[0].ID
params := &stripego.SubscriptionParams{
Items: []*stripego.SubscriptionItemsParams{
{ID: stripego.String(subItemID), Price: stripego.String(price100)},
},
ProrationBehavior: stripego.String("none"),
}
if _, err := subscription.Update(subID, params); err != nil {
log.Printf("webhook: failed to migrate sub %s to $100/mo: %v", subID, err)
return
}
log.Printf("webhook: migrated sub %s from $20/year to $100/month", subID)
}