forked from Nixius/authelia
97 lines
2.8 KiB
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)
|
|
}
|