Saving more details, redirecting and simplifying the succeed handler

This commit is contained in:
vinchent 2024-08-11 12:01:05 +02:00
parent 8e482aa712
commit 5ad4464b28
10 changed files with 124 additions and 49 deletions

View File

@ -21,14 +21,29 @@ func (app *application) VirtualTerminal(w http.ResponseWriter, r *http.Request)
} }
} }
func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request) { type TransactionData struct {
FirstName string
LastName string
Email string
PaymentIntentID string
PaymentMethodID string
PaymentAmount int
PaymentCurrency string
LastFour string
ExpiryMonth int
ExpiryYear int
BankReturnCode string
}
func (app *application) GetTransactionData(r *http.Request) (TransactionData, error) {
var txnData TransactionData
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
app.errorLog.Println(err) app.errorLog.Println(err)
return return txnData, err
} }
// read posted data
firstName := r.Form.Get("first_name") firstName := r.Form.Get("first_name")
lastName := r.Form.Get("last_name") lastName := r.Form.Get("last_name")
email := r.Form.Get("cardholder_email") email := r.Form.Get("cardholder_email")
@ -36,7 +51,9 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
paymentMethod := r.Form.Get("payment_method") paymentMethod := r.Form.Get("payment_method")
paymentAmount := r.Form.Get("payment_amount") paymentAmount := r.Form.Get("payment_amount")
paymentCurrency := r.Form.Get("payment_currency") paymentCurrency := r.Form.Get("payment_currency")
widgetID, _ := strconv.Atoi(r.Form.Get("product_id")) amount, _ := strconv.Atoi(paymentAmount)
// TODO: validation of the data
card := cards.Card{ card := cards.Card{
Secret: app.config.stripe.secret, Secret: app.config.stripe.secret,
@ -46,34 +63,67 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
pi, err := card.RetrievePaymentIntent(paymentIntent) pi, err := card.RetrievePaymentIntent(paymentIntent)
if err != nil { if err != nil {
app.errorLog.Println(err) app.errorLog.Println(err)
return return txnData, err
} }
pm, err := card.GetPaymentMethod(paymentMethod) pm, err := card.GetPaymentMethod(paymentMethod)
if err != nil { if err != nil {
app.errorLog.Println(err) app.errorLog.Println(err)
return return txnData, err
} }
lastFour := pm.Card.Last4 lastFour := pm.Card.Last4
expiryMonth := pm.Card.ExpMonth expiryMonth := pm.Card.ExpMonth
expiryYear := pm.Card.ExpYear expiryYear := pm.Card.ExpYear
customerID, err := app.SaveCustomer(firstName, lastName, email) txnData = TransactionData{
FirstName: firstName,
LastName: lastName,
Email: email,
PaymentIntentID: paymentIntent,
PaymentMethodID: paymentMethod,
PaymentAmount: amount,
PaymentCurrency: paymentCurrency,
LastFour: lastFour,
ExpiryMonth: int(expiryMonth),
ExpiryYear: int(expiryYear),
BankReturnCode: pi.LatestCharge.ID,
}
return txnData, nil
}
func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request) {
// read posted data
err := r.ParseForm()
if err != nil {
app.errorLog.Println(err)
return
}
widgetID, _ := strconv.Atoi(r.Form.Get("product_id"))
txnData, err := app.GetTransactionData(r)
if err != nil {
app.errorLog.Println(err)
return
}
customerID, err := app.SaveCustomer(txnData.FirstName, txnData.LastName, txnData.Email)
if err != nil { if err != nil {
app.errorLog.Println(err) app.errorLog.Println(err)
return return
} }
app.infoLog.Printf("custumer id: %d", customerID) app.infoLog.Printf("custumer id: %d", customerID)
amount, _ := strconv.Atoi(paymentAmount)
transaction := models.Transaction{ transaction := models.Transaction{
Amount: amount, Amount: txnData.PaymentAmount,
Currency: paymentCurrency, Currency: txnData.PaymentCurrency,
LastFour: lastFour, LastFour: txnData.LastFour,
ExpiryMonth: int(expiryMonth), ExpiryMonth: txnData.ExpiryMonth,
ExpiryYear: int(expiryYear), ExpiryYear: txnData.ExpiryYear,
BankReturnCode: pi.LatestCharge.ID, PaymentIntent: txnData.PaymentIntentID,
PaymentMethod: txnData.PaymentMethodID,
BankReturnCode: txnData.BankReturnCode,
TransactionStatusID: 2, // TODO: use an enum TransactionStatusID: 2, // TODO: use an enum
} }
@ -90,7 +140,7 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
CustomerID: customerID, CustomerID: customerID,
StatusID: 1, StatusID: 1,
Quantity: 1, Quantity: 1,
Amount: amount, Amount: txnData.PaymentAmount,
} }
orderID, err := app.SaveOrder(order) orderID, err := app.SaveOrder(order)
if err != nil { if err != nil {
@ -99,22 +149,16 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
} }
app.infoLog.Printf("order id: %d", orderID) app.infoLog.Printf("order id: %d", orderID)
app.Session.Put(r.Context(), "txn", txnData)
http.Redirect(w, r, "/receipt", http.StatusSeeOther)
}
func (app *application) Receipt(w http.ResponseWriter, r *http.Request) {
txn := app.Session.Pop(r.Context(), "txn").(TransactionData)
data := make(map[string]interface{}) data := make(map[string]interface{})
data["email"] = email data["txn"] = txn
data["pi"] = paymentIntent if err := app.renderTemplate(w, r, "receipt", &templateData{
data["pm"] = paymentMethod
data["pa"] = paymentAmount
data["pc"] = paymentCurrency
data["last_four"] = lastFour
data["expiry_month"] = expiryMonth
data["expiry_year"] = expiryYear
data["bank_return_code"] = pi.LatestCharge.ID
data["first_name"] = firstName
data["last_name"] = lastName
// should write this data to session, and then redirect user to the new page
if err := app.renderTemplate(w, r, "succeeded", &templateData{
Data: data, Data: data,
}); err != nil { }); err != nil {
app.errorLog.Println(err) app.errorLog.Println(err)

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/gob"
"flag" "flag"
"fmt" "fmt"
"html/template" "html/template"
@ -63,6 +64,8 @@ func (app *application) serve() error {
} }
func main() { func main() {
gob.Register(TransactionData{})
var cfg config var cfg config
flag.IntVar(&cfg.port, "port", 4000, "Server port to listen on") flag.IntVar(&cfg.port, "port", 4000, "Server port to listen on")

9
cmd/web/middleware.go Normal file
View File

@ -0,0 +1,9 @@
package main
import (
"net/http"
)
func SessionLoad(next http.Handler) http.Handler {
return session.LoadAndSave(next)
}

View File

@ -13,6 +13,7 @@ func (app *application) routes() http.Handler {
mux.Get("/", app.Home) mux.Get("/", app.Home)
mux.Get("/virtual-terminal", app.VirtualTerminal) mux.Get("/virtual-terminal", app.VirtualTerminal)
mux.Post("/payment-succeeded", app.PaymentSucceeded) mux.Post("/payment-succeeded", app.PaymentSucceeded)
mux.Get("/receipt", app.Receipt)
mux.Get("/widget/{id}", app.ChargeOnce) mux.Get("/widget/{id}", app.ChargeOnce)
fileServer := http.FileServer(http.Dir("./static")) fileServer := http.FileServer(http.Dir("./static"))

View File

@ -0,0 +1,8 @@
{{ template "base" . }}
{{ define "title" }}
Widget
{{ end }}
{{ define "content" }}
<h2 class="mt-5">Widget</h2>
{{ end }}

View File

@ -0,0 +1,18 @@
{{ template "base" . }}
{{ define "title" }}
Payment Succedded!
{{ end }}
{{ define "content" }}
{{$txn := index .Data "txn"}}
<h2 class="mt-5">Payment Succeeded</h2>
<hr>
<p>Payment Intent: {{$txn.PaymentIntentID}}</p>
<p>Customer Name: {{ $txn.FirstName }} {{ $txn.LastName }}</p>
<p>Email: {{ $txn.Email }}</p>
<p>Payment Method: {{ $txn.PaymentMethodID }}</p>
<p>Payment Amount: {{ $txn.PaymentAmount }}</p>
<p>Currency: {{ $txn.PaymentCurrency }}</p>
<p>Last Four: {{ $txn.LastFour }}</p>
<p>Bank Return Code: {{ $txn.BankReturnCode }}</p>
<p>Expiry Date: {{ $txn.ExpiryMonth }}/{{$txn.ExpiryYear}}</p>
{{ end }}

View File

@ -1,17 +0,0 @@
{{ template "base" . }}
{{ define "title" }}
Payment Succedded!
{{ end }}
{{ define "content" }}
<h2 class="mt-5">Payment Succeeded</h2>
<hr>
<p>Payment Intent: {{ index .Data "pi" }}</p>
<p>Customer Name: {{ index .Data "first_name" }} {{ index .Data "last_name" }}</p>
<p>Email: {{ index .Data "email" }}</p>
<p>Payment Method: {{ index .Data "pm" }}</p>
<p>Payment Amount: {{ index .Data "pa" }}</p>
<p>Currency: {{ index .Data "pc" }}</p>
<p>Last Four: {{ index .Data "last_four" }}</p>
<p>Bank Return Code: {{ index .Data "bank_return_code" }}</p>
<p>Expiry Date: {{ index .Data "expiry_month" }}/{{index .Data "expiry_year"}}</p>
{{ end }}

View File

@ -72,6 +72,8 @@ type Transaction struct {
LastFour string `json:"last_four"` LastFour string `json:"last_four"`
ExpiryMonth int `json:"expiry_month"` ExpiryMonth int `json:"expiry_month"`
ExpiryYear int `json:"expiry_year"` ExpiryYear int `json:"expiry_year"`
PaymentIntent string `json:"payment_intent"`
PaymentMethod string `json:"payment_method"`
BankReturnCode string `json:"bank_return_code"` BankReturnCode string `json:"bank_return_code"`
TransactionStatusID int `json:"transaction_status_id"` TransactionStatusID int `json:"transaction_status_id"`
CreatedAt time.Time `json:"-"` CreatedAt time.Time `json:"-"`
@ -134,9 +136,9 @@ func (m *DBModel) InsertTransaction(txn Transaction) (int, error) {
stmt := `INSERT INTO transactions stmt := `INSERT INTO transactions
(amount, currency, last_four, expiry_month, expiry_year, (amount, currency, last_four, expiry_month, expiry_year,
bank_return_code, payment_intent, payment_method, bank_return_code,
transaction_status_id, created_at, updated_at) transaction_status_id, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)` VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
result, err := m.DB.ExecContext(ctx, stmt, result, err := m.DB.ExecContext(ctx, stmt,
txn.Amount, txn.Amount,
@ -144,6 +146,8 @@ func (m *DBModel) InsertTransaction(txn Transaction) (int, error) {
txn.LastFour, txn.LastFour,
txn.ExpiryMonth, txn.ExpiryMonth,
txn.ExpiryYear, txn.ExpiryYear,
txn.PaymentIntent,
txn.PaymentMethod,
txn.BankReturnCode, txn.BankReturnCode,
txn.TransactionStatusID, txn.TransactionStatusID,
time.Now(), time.Now(),

View File

@ -0,0 +1,2 @@
drop_column("transactions", "payment_intent")
drop_column("transactions", "payment_method")

View File

@ -0,0 +1,3 @@
add_column("transactions", "payment_intent", "string", {"default":""})
add_column("transactions", "payment_method", "string", {"default":""})