|
|
@@ -75,6 +75,7 @@ type Subscription struct { |
|
|
|
End int `json:"end"` |
|
|
|
ClientSecret string `json:"clientSecret,omitempty"` |
|
|
|
PaymentStatus string `json:"paymentStatus"` |
|
|
|
Status string `json:"status"` |
|
|
|
} |
|
|
|
|
|
|
|
type User struct { |
|
|
@@ -236,6 +237,9 @@ type Endpoint func(http.ResponseWriter, *sql.DB, *http.Request) |
|
|
|
type HookKeys struct { |
|
|
|
InvoicePaid string |
|
|
|
InvoiceFailed string |
|
|
|
SubCreated string |
|
|
|
SubUpdated string |
|
|
|
SubDeleted string |
|
|
|
} |
|
|
|
|
|
|
|
var ( |
|
|
@@ -265,6 +269,15 @@ var roles = map[string]int{ |
|
|
|
"Admin": 3, |
|
|
|
} |
|
|
|
|
|
|
|
var statuses = map[string]int{ |
|
|
|
"Unsubscribed": 1, |
|
|
|
"Trial": 2, |
|
|
|
"Free": 3, |
|
|
|
"Subscriber": 4, |
|
|
|
"Branch": 5, |
|
|
|
"Admin": 6, |
|
|
|
} |
|
|
|
|
|
|
|
var propertyTypes = []string{ |
|
|
|
"Single Detached", |
|
|
|
"Single Attached", |
|
|
@@ -283,6 +296,9 @@ var feeTypes = []string{ |
|
|
|
var hookKeys = HookKeys{ |
|
|
|
InvoicePaid: "", |
|
|
|
InvoiceFailed: "", |
|
|
|
SubCreated: "", |
|
|
|
SubUpdated: "", |
|
|
|
SubDeleted: "", |
|
|
|
} |
|
|
|
|
|
|
|
var standardPriceId = "price_1OZLK9BPMoXn2pf9kuTAf8rs" |
|
|
@@ -1485,9 +1501,10 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) { |
|
|
|
current_period_end, |
|
|
|
current_period_start, |
|
|
|
client_secret, |
|
|
|
payment_status |
|
|
|
payment_status, |
|
|
|
status |
|
|
|
) |
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?) |
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) |
|
|
|
RETURNING id |
|
|
|
` |
|
|
|
|
|
|
@@ -1500,6 +1517,7 @@ func (sub *Subscription) insertSub(db *sql.DB) (error) { |
|
|
|
sub.Start, |
|
|
|
sub.ClientSecret, |
|
|
|
sub.PaymentStatus, |
|
|
|
sub.Status, |
|
|
|
) |
|
|
|
|
|
|
|
err = row.Scan(&sub.Id) |
|
|
@@ -1511,7 +1529,7 @@ func (sub *Subscription) updateSub(db *sql.DB) error { |
|
|
|
var err error |
|
|
|
|
|
|
|
query = `UPDATE subscription |
|
|
|
SET client_secret = ?, payment_status = ? |
|
|
|
SET client_secret = ?, payment_status = ?, |
|
|
|
WHERE id = ? |
|
|
|
` |
|
|
|
|
|
|
@@ -1585,7 +1603,7 @@ func updateAddress(address Address, db *sql.DB) error { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
func updateUser(user User, db *sql.DB) error { |
|
|
|
func (user *User) update(db *sql.DB) error { |
|
|
|
query := ` |
|
|
|
UPDATE user |
|
|
|
SET |
|
|
@@ -1647,7 +1665,7 @@ func setUser(user User, db *sql.DB) error { |
|
|
|
return errors.New("Invalid role") |
|
|
|
} |
|
|
|
|
|
|
|
err = updateUser(user, db) |
|
|
|
err = user.update(db) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
@@ -3069,23 +3087,19 @@ func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) { |
|
|
|
user.Sub.ClientSecret = s.LatestInvoice.PaymentIntent.ClientSecret |
|
|
|
user.Sub.PaymentStatus = string(s.LatestInvoice.PaymentIntent.Status) |
|
|
|
|
|
|
|
// Inserting from here is probably unnecessary and confusing because |
|
|
|
// new subs are already handled by the stripe hook |
|
|
|
err = user.Sub.insertSub(db) |
|
|
|
if err != nil { |
|
|
|
http.Error(w, err.Error(), 500) |
|
|
|
return |
|
|
|
} |
|
|
|
json.NewEncoder(w).Encode(user.Sub) |
|
|
|
} else { |
|
|
|
err = user.Sub.updateSub(db) |
|
|
|
if err != nil { |
|
|
|
http.Error(w, err.Error(), 500) |
|
|
|
return |
|
|
|
} |
|
|
|
json.NewEncoder(w).Encode(user.Sub) |
|
|
|
// This should handle creating a new subscription when the old one |
|
|
|
// has an incomplete_expired status and cannot be paid |
|
|
|
} |
|
|
|
|
|
|
|
// Should check that subscription is still valid and has payment intent |
|
|
|
// here |
|
|
|
json.NewEncoder(w).Encode(user.Sub) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
@@ -3132,7 +3146,6 @@ func invoicePaid(w http.ResponseWriter, db *sql.DB, r *http.Request) { |
|
|
|
} |
|
|
|
|
|
|
|
log.Println(user.Id, s.ID) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func invoiceFailed(w http.ResponseWriter, db *sql.DB, r *http.Request) { |
|
|
@@ -3154,6 +3167,77 @@ func invoiceFailed(w http.ResponseWriter, db *sql.DB, r *http.Request) { |
|
|
|
log.Println(event.Data) |
|
|
|
} |
|
|
|
|
|
|
|
// A successful subscription payment should be confirmed by Stripe and |
|
|
|
// Updated through this hook. |
|
|
|
func subCreated(w http.ResponseWriter, db *sql.DB, r *http.Request) { |
|
|
|
|
|
|
|
var sub stripe.Subscription |
|
|
|
b, err := io.ReadAll(r.Body) |
|
|
|
if err != nil { |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
log.Printf("io.ReadAll: %v", err) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
event, err := webhook.ConstructEvent(b, |
|
|
|
r.Header.Get("Stripe-Signature"), |
|
|
|
hookKeys.SubCreated) |
|
|
|
if err != nil { |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
log.Printf("webhook.ConstructEvent: %v", err) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// OK should be sent before any processing to confirm with Stripe that |
|
|
|
// the hook was received |
|
|
|
w.WriteHeader(http.StatusOK) |
|
|
|
if event.Type != "customer.subscription.created" { |
|
|
|
log.Println( |
|
|
|
"Invalid event type sent to customer.subscription.created.") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
json.Unmarshal(event.Data.Raw, &sub) |
|
|
|
log.Println(event.Type, sub.ID, sub.Customer.ID) |
|
|
|
|
|
|
|
user, err := queryCustomer(db, sub.Customer.ID) |
|
|
|
if err != nil { |
|
|
|
log.Printf("Could not query customer: %v", err) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if statuses[user.Status] < 5 && sub.Status == "trialing" { |
|
|
|
user.Status = "Trial" |
|
|
|
user.update(db) |
|
|
|
} else if sub.Status != "active" { |
|
|
|
user.Status = "Unsubscribed" |
|
|
|
user.update(db) |
|
|
|
} |
|
|
|
|
|
|
|
user.Sub.UserId = user.Id |
|
|
|
user.Sub.StripeId = sub.ID |
|
|
|
user.Sub.CustomerId = user.CustomerId |
|
|
|
user.Sub.PriceId = standardPriceId |
|
|
|
user.Sub.End = int(sub.CurrentPeriodEnd) |
|
|
|
user.Sub.Start = int(sub.CurrentPeriodStart) |
|
|
|
user.Sub.ClientSecret = sub.LatestInvoice.PaymentIntent.ClientSecret |
|
|
|
user.Sub.PaymentStatus = string(sub.LatestInvoice.PaymentIntent.Status) |
|
|
|
user.Sub.Status = string(sub.Status) |
|
|
|
|
|
|
|
if user.Sub.Id > 0 { |
|
|
|
user.Sub.updateSub(db) |
|
|
|
} else { |
|
|
|
err = user.Sub.insertSub(db) |
|
|
|
} |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
http.Error(w, err.Error(), 500) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
log.Println("User subscription created:", user.Id, sub.ID) |
|
|
|
} |
|
|
|
|
|
|
|
func api(w http.ResponseWriter, r *http.Request) { |
|
|
|
var args []string |
|
|
|
|
|
|
@@ -3443,7 +3527,7 @@ func seedUsers(db *sql.DB, addresses []Address, branches []Branch) []User { |
|
|
|
users[i].Password = "test123" |
|
|
|
users[i].Verified = true |
|
|
|
users[i].Title = "Loan Officer" |
|
|
|
users[i].Status = "Subscribed" |
|
|
|
users[i].Status = "Subscriber" |
|
|
|
users[i].Role = "User" |
|
|
|
} |
|
|
|
|
|
|
|