mini-beieli-web/stripe.go

166 lines
5.0 KiB
Go

package main
import (
"encoding/json"
"fmt"
"github.com/stripe/stripe-go/v74"
"github.com/stripe/stripe-go/v74/customer"
"github.com/stripe/stripe-go/v74/paymentintent"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"strings"
)
func getStripeKey() string {
return os.Getenv("STRIPE_KEY")
}
func getStripePK() string {
return os.Getenv("STRIPE_PK")
}
func getCustomerid(name string) string {
// if customer does not already exist, create it...
var cid = ""
params := &stripe.CustomerSearchParams{}
params.Query = *stripe.String("name:'" + name + "'")
customers := customer.Search(params)
for customers.Next() {
fmt.Printf("%s\n", customers.Current().(*stripe.Customer).ID)
cid = customers.Current().(*stripe.Customer).ID
}
if cid == "" {
// create new customer
paramsc := &stripe.CustomerParams{
Name: stripe.String(name),
}
customer, err := customer.New(paramsc)
if err != nil {
log.Println("Error Creating Customer: " + name)
}
cid = customer.ID
}
return cid
}
func getstripepaymentintentHandler(response http.ResponseWriter, request *http.Request) {
name := getUserName(request)
if name != "" {
charge_data, ok := request.URL.Query()["charge_data"]
if !ok || len(charge_data[0]) < 1 {
log.Println("Url Param 'charge_data' is missing")
fmt.Fprintf(response, "{ \"rc\": 1, \"msg\": \"charge_data must be specified in URL\" }")
return
}
scales := strings.Split(charge_data[0], ",")
var abo_years = 0
var items []string
amount := 0
for _, scale := range scales {
items = strings.Split(scale, ":")
if len(items) >= 2 {
abo_count, err := strconv.Atoi(items[1])
if err == nil {
abo_years += abo_count
amount += (abo_count * getYearlyAboCost(items[0]))
}
}
}
abo_amount := int64(amount)
stripe.Key = getStripeKey()
// if customer does not already exist, create it...
customerid := getCustomerid(name)
// define payment
params := &stripe.PaymentIntentParams{
Customer: stripe.String(customerid),
Amount: stripe.Int64(abo_amount),
Currency: stripe.String(string(stripe.CurrencyCHF)),
}
params.AddMetadata("charge_data", charge_data[0])
params.AddMetadata("login_user", name)
paymentintent, err := paymentintent.New(params)
if err != nil {
fmt.Fprintf(response, "{ \"rc\": 5, \"stripeclientsecret\": \"%s\" }\n", err)
} else {
fmt.Fprintf(response, "{ \"rc\": 0, \"stripeclientsecret\": \"%s\" }\n", paymentintent.ClientSecret)
}
} else {
fmt.Fprintf(response, "{ \"rc\": 6, \"msg\": \"Only available for logged in users\" }")
}
}
func HandlePayment(user string, charge_data string, amount int64) {
fmt.Printf("HandlePayment for %s (charge_data: %s, amount: %d)!\n", user, charge_data, amount)
charge_data_email_text := fmt.Sprintf("%-30s %20s %10s\n", "Alias", "verlängern bis", "Betrag")
charge_data_email_text = charge_data_email_text + strings.Repeat("-", 62) + "\n"
for _, token := range strings.Split(charge_data, ",") {
res := strings.Split(token, ":")
if (len(res)) == 3 {
deveui := res[0]
years, _ := strconv.Atoi(res[1])
amount, _ := strconv.Atoi(res[2])
fmt.Printf("prolongActivation %s: %d\n", deveui, years)
prolongActivation(deveui, years)
line := fmt.Sprintf("%-30s %20s %10.2f\n", getDevAlias(deveui), getActiveUntil(deveui), float64(amount/100))
charge_data_email_text = charge_data_email_text + line
}
}
charge_data_email_text = charge_data_email_text + strings.Repeat("-", 62) + "\n"
charge_data_email_text = charge_data_email_text + fmt.Sprintf("%-30s %20s %10.2f\n", "Total CHF", "", float64(amount/100))
sendPaymentConfirmationEmail(user, charge_data_email_text, amount)
}
func stripeWebhookHandler(w http.ResponseWriter, req *http.Request) {
const MaxBodyBytes = int64(65536)
req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes)
payload, err := ioutil.ReadAll(req.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
event := stripe.Event{}
if err := json.Unmarshal(payload, &event); err != nil {
fmt.Fprintf(os.Stderr, "Failed to parse webhook body json: %v\n", err.Error())
w.WriteHeader(http.StatusBadRequest)
return
}
// Unmarshal the event data into an appropriate struct depending on its Type
switch event.Type {
case "payment_intent.succeeded":
var paymentIntent stripe.PaymentIntent
err := json.Unmarshal(event.Data.Raw, &paymentIntent)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
fmt.Printf("PaymentIntent was successful (charge_data: %s, amount: %d)!\n", paymentIntent.Metadata["charge_data"], paymentIntent.Amount)
HandlePayment(paymentIntent.Metadata["login_user"], paymentIntent.Metadata["charge_data"], paymentIntent.Amount)
// ... handle other event types
default:
fmt.Fprintf(os.Stderr, "Unexpected event type: %s\n", event.Type)
w.WriteHeader(http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusOK)
}