save orders
This commit is contained in:
parent
88be25d77f
commit
8e482aa712
@ -2,12 +2,19 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"myapp/internal/cards"
|
"myapp/internal/cards"
|
||||||
|
"myapp/internal/models"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (app *application) Home(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := app.renderTemplate(w, r, "home", &templateData{}); err != nil {
|
||||||
|
app.errorLog.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (app *application) VirtualTerminal(w http.ResponseWriter, r *http.Request) {
|
func (app *application) VirtualTerminal(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := app.renderTemplate(w, r, "terminal", &templateData{}); err != nil {
|
if err := app.renderTemplate(w, r, "terminal", &templateData{}); err != nil {
|
||||||
app.errorLog.Println(err)
|
app.errorLog.Println(err)
|
||||||
@ -22,12 +29,14 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read posted data
|
// read posted data
|
||||||
cardHolder := r.Form.Get("cardholder_name")
|
firstName := r.Form.Get("first_name")
|
||||||
|
lastName := r.Form.Get("last_name")
|
||||||
email := r.Form.Get("cardholder_email")
|
email := r.Form.Get("cardholder_email")
|
||||||
paymentIntent := r.Form.Get("payment_intent")
|
paymentIntent := r.Form.Get("payment_intent")
|
||||||
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"))
|
||||||
|
|
||||||
card := cards.Card{
|
card := cards.Card{
|
||||||
Secret: app.config.stripe.secret,
|
Secret: app.config.stripe.secret,
|
||||||
@ -50,8 +59,47 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
|
|||||||
expiryMonth := pm.Card.ExpMonth
|
expiryMonth := pm.Card.ExpMonth
|
||||||
expiryYear := pm.Card.ExpYear
|
expiryYear := pm.Card.ExpYear
|
||||||
|
|
||||||
|
customerID, err := app.SaveCustomer(firstName, lastName, email)
|
||||||
|
if err != nil {
|
||||||
|
app.errorLog.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.infoLog.Printf("custumer id: %d", customerID)
|
||||||
|
|
||||||
|
amount, _ := strconv.Atoi(paymentAmount)
|
||||||
|
transaction := models.Transaction{
|
||||||
|
Amount: amount,
|
||||||
|
Currency: paymentCurrency,
|
||||||
|
LastFour: lastFour,
|
||||||
|
ExpiryMonth: int(expiryMonth),
|
||||||
|
ExpiryYear: int(expiryYear),
|
||||||
|
BankReturnCode: pi.LatestCharge.ID,
|
||||||
|
TransactionStatusID: 2, // TODO: use an enum
|
||||||
|
}
|
||||||
|
|
||||||
|
txnID, err := app.SaveTransaction(transaction)
|
||||||
|
if err != nil {
|
||||||
|
app.errorLog.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.infoLog.Printf("transaction id: %d", txnID)
|
||||||
|
|
||||||
|
order := models.Order{
|
||||||
|
WidgetID: widgetID,
|
||||||
|
TransactionID: txnID,
|
||||||
|
CustomerID: customerID,
|
||||||
|
StatusID: 1,
|
||||||
|
Quantity: 1,
|
||||||
|
Amount: amount,
|
||||||
|
}
|
||||||
|
orderID, err := app.SaveOrder(order)
|
||||||
|
if err != nil {
|
||||||
|
app.errorLog.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.infoLog.Printf("order id: %d", orderID)
|
||||||
|
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data["cardholder"] = cardHolder
|
|
||||||
data["email"] = email
|
data["email"] = email
|
||||||
data["pi"] = paymentIntent
|
data["pi"] = paymentIntent
|
||||||
data["pm"] = paymentMethod
|
data["pm"] = paymentMethod
|
||||||
@ -61,6 +109,10 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
|
|||||||
data["expiry_month"] = expiryMonth
|
data["expiry_month"] = expiryMonth
|
||||||
data["expiry_year"] = expiryYear
|
data["expiry_year"] = expiryYear
|
||||||
data["bank_return_code"] = pi.LatestCharge.ID
|
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{
|
if err := app.renderTemplate(w, r, "succeeded", &templateData{
|
||||||
Data: data,
|
Data: data,
|
||||||
@ -69,6 +121,41 @@ func (app *application) PaymentSucceeded(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *application) SaveCustomer(firstName, lastName, email string) (int, error) {
|
||||||
|
customer := models.Customer{
|
||||||
|
FirstName: firstName,
|
||||||
|
LastName: lastName,
|
||||||
|
Email: email,
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := app.DB.InsertCustomer(customer)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *application) SaveTransaction(txn models.Transaction) (int, error) {
|
||||||
|
txnID, err := app.DB.InsertTransaction(txn)
|
||||||
|
if err != nil {
|
||||||
|
app.errorLog.Println(err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return txnID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *application) SaveOrder(order models.Order) (int, error) {
|
||||||
|
id, err := app.DB.InsertOrder(order)
|
||||||
|
if err != nil {
|
||||||
|
app.errorLog.Println(err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChargeOnce displays the page to buy one widget
|
// ChargeOnce displays the page to buy one widget
|
||||||
func (app *application) ChargeOnce(w http.ResponseWriter, r *http.Request) {
|
func (app *application) ChargeOnce(w http.ResponseWriter, r *http.Request) {
|
||||||
id := chi.URLParam(r, "id")
|
id := chi.URLParam(r, "id")
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/alexedwards/scs/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -17,6 +19,8 @@ const (
|
|||||||
cssVersion = "1"
|
cssVersion = "1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var session *scs.SessionManager
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
port int
|
port int
|
||||||
env string
|
env string
|
||||||
@ -37,6 +41,7 @@ type application struct {
|
|||||||
templateCache map[string]*template.Template
|
templateCache map[string]*template.Template
|
||||||
version string
|
version string
|
||||||
DB models.DBModel
|
DB models.DBModel
|
||||||
|
Session *scs.SessionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *application) serve() error {
|
func (app *application) serve() error {
|
||||||
@ -83,6 +88,10 @@ func main() {
|
|||||||
infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
|
infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
|
||||||
errorLog := log.New(os.Stdout, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)
|
errorLog := log.New(os.Stdout, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)
|
||||||
|
|
||||||
|
// set up session
|
||||||
|
session = scs.New()
|
||||||
|
session.Lifetime = 24 * time.Hour
|
||||||
|
|
||||||
conn, err := driver.OpenDB(cfg.db.dsn)
|
conn, err := driver.OpenDB(cfg.db.dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorLog.Fatal(err)
|
errorLog.Fatal(err)
|
||||||
@ -98,6 +107,7 @@ func main() {
|
|||||||
templateCache: tc,
|
templateCache: tc,
|
||||||
version: version,
|
version: version,
|
||||||
DB: models.DBModel{DB: conn},
|
DB: models.DBModel{DB: conn},
|
||||||
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.infoLog.Println("Connected to MariaDB")
|
app.infoLog.Println("Connected to MariaDB")
|
||||||
|
@ -8,7 +8,9 @@ import (
|
|||||||
|
|
||||||
func (app *application) routes() http.Handler {
|
func (app *application) routes() http.Handler {
|
||||||
mux := chi.NewRouter()
|
mux := chi.NewRouter()
|
||||||
|
mux.Use(SessionLoad)
|
||||||
|
|
||||||
|
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("/widget/{id}", app.ChargeOnce)
|
mux.Get("/widget/{id}", app.ChargeOnce)
|
||||||
|
@ -23,7 +23,33 @@ Buy one widget
|
|||||||
<p class="mt-2 mb-3 text-center">{{$widget.Description}}</p>
|
<p class="mt-2 mb-3 text-center">{{$widget.Description}}</p>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="cardholder-name" class="form-label">Cardholder Name</label>
|
<label for="first-name" class="form-label">First Name</label>
|
||||||
|
<input type="text"
|
||||||
|
id="first-name"
|
||||||
|
name="first_name"
|
||||||
|
autocomplete="first-name-new"
|
||||||
|
required=""
|
||||||
|
class="form-control">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="last-name" class="form-label">Last Name</label>
|
||||||
|
<input type="text"
|
||||||
|
id="last-name"
|
||||||
|
name="last_name"
|
||||||
|
autocomplete="last-name-new"
|
||||||
|
required=""
|
||||||
|
class="form-control">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="cardholder-email" class="form-label">Email</label>
|
||||||
|
<input type="text"
|
||||||
|
id="cardholder-email"
|
||||||
|
name="cardholder_email"
|
||||||
|
autocomplete="cardholder-email-new"
|
||||||
|
required=""
|
||||||
|
class="form-control">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="cardholder-name" class="form-label">Name on card</label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
id="cardholder-name"
|
id="cardholder-name"
|
||||||
name="cardholder_name"
|
name="cardholder_name"
|
||||||
@ -31,14 +57,6 @@ Buy one widget
|
|||||||
required=""
|
required=""
|
||||||
class="form-control">
|
class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
|
||||||
<label for="cardholder-email" class="form-label">Cardholder Email</label>
|
|
||||||
<input type="text"
|
|
||||||
id="cardholder-email"
|
|
||||||
name="cardholder_email"
|
|
||||||
autocomplete="cardholder-email-new"
|
|
||||||
required=""
|
|
||||||
class="form-control">
|
|
||||||
</div>
|
</div>
|
||||||
<!-- card number will be built by stripe -->
|
<!-- card number will be built by stripe -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@ -6,7 +6,7 @@ Payment Succedded!
|
|||||||
<h2 class="mt-5">Payment Succeeded</h2>
|
<h2 class="mt-5">Payment Succeeded</h2>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Payment Intent: {{ index .Data "pi" }}</p>
|
<p>Payment Intent: {{ index .Data "pi" }}</p>
|
||||||
<p>Cardholder: {{ index .Data "cardholder" }}</p>
|
<p>Customer Name: {{ index .Data "first_name" }} {{ index .Data "last_name" }}</p>
|
||||||
<p>Email: {{ index .Data "email" }}</p>
|
<p>Email: {{ index .Data "email" }}</p>
|
||||||
<p>Payment Method: {{ index .Data "pm" }}</p>
|
<p>Payment Method: {{ index .Data "pm" }}</p>
|
||||||
<p>Payment Amount: {{ index .Data "pa" }}</p>
|
<p>Payment Amount: {{ index .Data "pa" }}</p>
|
||||||
|
5
go.mod
5
go.mod
@ -9,4 +9,7 @@ require (
|
|||||||
github.com/stripe/stripe-go/v79 v79.6.0
|
github.com/stripe/stripe-go/v79 v79.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require filippo.io/edwards25519 v1.1.0 // indirect
|
require (
|
||||||
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
|
github.com/alexedwards/scs/v2 v2.8.0 // indirect
|
||||||
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -1,5 +1,7 @@
|
|||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw=
|
||||||
|
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||||
|
@ -70,6 +70,8 @@ type Transaction struct {
|
|||||||
Amount int `json:"amount"`
|
Amount int `json:"amount"`
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
LastFour string `json:"last_four"`
|
LastFour string `json:"last_four"`
|
||||||
|
ExpiryMonth int `json:"expiry_month"`
|
||||||
|
ExpiryYear int `json:"expiry_year"`
|
||||||
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:"-"`
|
||||||
@ -131,14 +133,17 @@ func (m *DBModel) InsertTransaction(txn Transaction) (int, error) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
stmt := `INSERT INTO transactions
|
stmt := `INSERT INTO transactions
|
||||||
(amount, currency, last_four, bank_return_code,
|
(amount, currency, last_four, expiry_month, expiry_year,
|
||||||
|
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,
|
||||||
txn.Currency,
|
txn.Currency,
|
||||||
txn.LastFour,
|
txn.LastFour,
|
||||||
|
txn.ExpiryMonth,
|
||||||
|
txn.ExpiryYear,
|
||||||
txn.BankReturnCode,
|
txn.BankReturnCode,
|
||||||
txn.TransactionStatusID,
|
txn.TransactionStatusID,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
@ -160,17 +165,45 @@ func (m *DBModel) InsertOrder(order Order) (int, error) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
stmt := `INSERT INTO orders
|
stmt := `INSERT INTO orders
|
||||||
(widget_id, transaction_id, status_id, quantity,
|
(widget_id, transaction_id, customer_id, status_id, quantity,
|
||||||
amount, created_at, updated_at)
|
amount, created_at, updated_at)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
result, err := m.DB.ExecContext(ctx, stmt,
|
result, err := m.DB.ExecContext(ctx, stmt,
|
||||||
order.WidgetID,
|
order.WidgetID,
|
||||||
order.TransactionID,
|
order.TransactionID,
|
||||||
|
order.CustomerID,
|
||||||
order.StatusID,
|
order.StatusID,
|
||||||
order.Quantity,
|
order.Quantity,
|
||||||
order.Amount,
|
order.Amount,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
|
time.Now(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
id, err := result.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(id), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertCustomer inserts a new customer, and returns its id
|
||||||
|
func (m *DBModel) InsertCustomer(customer Customer) (int, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
stmt := `INSERT INTO customers
|
||||||
|
(first_name, last_name, email, created_at, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
|
result, err := m.DB.ExecContext(ctx, stmt,
|
||||||
|
customer.FirstName,
|
||||||
|
customer.LastName,
|
||||||
|
customer.Email,
|
||||||
|
time.Now(),
|
||||||
|
time.Now(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
Loading…
Reference in New Issue
Block a user