Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/razorpay/razorpay-go v1.3.2 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/net v0.33.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/a-h/templ v0.3.819 h1:KDJ5jTFN15FyJnmSmo2gNirIqt7hfvBD2VXVDTySckM=
github.com/a-h/templ v0.3.819/go.mod h1:iDJKJktpttVKdWoTkRNNLcllRI+BlpopJc+8au3gOUo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
Expand Down Expand Up @@ -35,6 +36,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/razorpay/razorpay-go v1.3.2 h1:6368QznCNkoQNi7bBbxdHUu7lJJW4UxN7W3WftrbFZg=
github.com/razorpay/razorpay-go v1.3.2/go.mod h1:VcljkUylUJAUEvFfGVv/d5ht1to1dUgF4H1+3nv7i+Q=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
Expand All @@ -53,5 +58,7 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
80 changes: 77 additions & 3 deletions internal/handler/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handler
import (
"fmt"
"net/http"
"os"

"github.com/FulgurCode/stitch/models"
"github.com/FulgurCode/stitch/pkg/mysql"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/FulgurCode/stitch/view/user"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/razorpay/razorpay-go"
)

// Home page handler
Expand Down Expand Up @@ -87,18 +89,40 @@ func OrderPost(c echo.Context) error {
}

order.ProductId = productId
order.Status = "ordered"
if order.Payment == "online" {
order.Status = "pending"
} else {
order.Status = "ordered"
}
if order.Quantity == 0 {
order.Quantity = 1
}
order.Total = product.Price * order.Quantity

var orderId = uuid.New()
order.Id = string(orderId.String())
err = mysql.MakeOrder(order, orderId)
if err != nil {
fmt.Println(err)
}

if order.Payment == "online" {
var key = os.Getenv("RAZORPAY_KEY")
var secret = os.Getenv("RAZORPAY_SECRET")
var client = razorpay.NewClient(key, secret)
var ord = map[string]interface{}{
"amount": order.Total * 100,
"currency": "INR",
}
body, err := client.Order.Create(ord, nil)
if err != nil {
fmt.Println(err)
}

var component = user.OnlinePayment(order, body, key)
return utils.Render(c, component)
}

if c.Request().Header.Get("HX-Request") == "true" {
c.Response().Header().Set("HX-Location", fmt.Sprintf("/item/%s", productId))
return c.NoContent(http.StatusSeeOther)
Expand Down Expand Up @@ -199,12 +223,18 @@ func CartOrderPost(c echo.Context) error {

var cart = utils.GetSessionAll(c, "cart")
var orderId = uuid.New()
body.Id = orderId.String()
var total int = 0
for id, size := range cart {
var product, _ = mysql.GetProductById(id.(string))
var order models.Order = body

order.ProductId = product.Id
order.Status = "ordered"
if body.Payment == "online" {
order.Status = "pending"
} else {
order.Status = "ordered"
}
order.Quantity = 1
order.Total = product.Price
order.Size = size.(string)
Expand All @@ -213,9 +243,25 @@ func CartOrderPost(c echo.Context) error {
if err != nil {
fmt.Println(err)
}
total += order.Total
}
if body.Payment == "online" {
var key = os.Getenv("RAZORPAY_KEY")
var secret = os.Getenv("RAZORPAY_SECRET")
var client = razorpay.NewClient(key, secret)
var ord = map[string]interface{}{
"amount": total * 100,
"currency": "INR",
}
order, err := client.Order.Create(ord, nil)
if err != nil {
fmt.Println(err)
}
fmt.Println("submit cart")

utils.DeleteSession(c, "cart")
var component = user.OnlinePaymentCart(body, order, key)
return utils.Render(c, component)
}

if c.Request().Header.Get("HX-Request") == "true" {
c.Response().Header().Set("HX-Location", "/cart")
Expand All @@ -224,3 +270,31 @@ func CartOrderPost(c echo.Context) error {

return c.Redirect(http.StatusSeeOther, "/cart")
}

func VerifyOnlinePayment(c echo.Context) error {
var orderId = c.Param("orderId")
var data models.VerifyOrder
var err = c.Bind(&data)
if err != nil {
fmt.Println(err)
}

if err := utils.RazorPaymentVerification(data); err == nil {
mysql.OrderStatusPayment(orderId, "ordered")
return c.JSON(200, "Ordered Successfully And Payment Verified")
}

fmt.Println(err)
return c.JSON(406, "Payment Verification Failed")
}

func DeletePendingOrder(c echo.Context) error {
var orderId = c.Param("orderId")
var err = mysql.DeletePendingOrder(orderId)
if err != nil {
fmt.Println(err)
return c.JSON(500, "Failed")
}

return c.JSON(200, "Order Payment Failed / Cancelled")
}
6 changes: 6 additions & 0 deletions models/product.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ type Order struct {
Total int `json:"total" form:"total"`
Status string `json:"status" form:"status"`
}

type VerifyOrder struct {
OrderId string `json:"orderId" form:"orderId"`
PaymentId string `json:"paymentId" form:"paymentId"`
RazorpaySignature string `json:"razorpaySignature" form:"razorpaySignature"`
}
12 changes: 12 additions & 0 deletions pkg/mysql/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,15 @@ func DeleteOrder(id string, productId string) error {
var _, err = Db.Exec(query, id, productId)
return err
}

func OrderStatusPayment(id string, status string) error {
var query = "UPDATE orders SET status = ? WHERE id = ?;"
var _, err = Db.Exec(query, status, id)
return err
}

func DeletePendingOrder(id string) error {
var query = "DELETE FROM orders WHERE id = ? AND status = 'pending';"
var _, err = Db.Exec(query, id)
return err
}
2 changes: 2 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func Run(port string) {
app.POST("/cart/order", handler.CartOrderPost)
app.GET("add-to-cart/:productId", handler.AddToCart)
app.DELETE("delete-cart/:productId", handler.DeleteFromCart)
app.POST("/payment-verification/:orderId", handler.VerifyOnlinePayment)
app.GET("/delete-order/:orderId", handler.DeletePendingOrder)

app.GET("/admin", utils.CheckLogin(handler.Admin))

Expand Down
31 changes: 31 additions & 0 deletions utils/razorpay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package utils

import (
"crypto/hmac"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"errors"
"os"

"github.com/FulgurCode/stitch/models"
)

func RazorPaymentVerification(order models.VerifyOrder) error {
var secret = os.Getenv("RAZORPAY_SECRET")
data := order.OrderId+ "|" + order.PaymentId

h := hmac.New(sha256.New, []byte(secret))

_, err := h.Write([]byte(data))
if err != nil {
panic(err)
}

sha := hex.EncodeToString(h.Sum(nil))
if subtle.ConstantTimeCompare([]byte(sha), []byte(order.RazorpaySignature)) != 1 {
return errors.New("Payment failed")
} else {
return nil
}
}
63 changes: 61 additions & 2 deletions view/user/cart-order.templ
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

templ CartOrder(products []models.Product) {
@layout.User() {
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<link rel="stylesheet" href="/static/styles/user/cart-order.css">
<div class={Container()}>
<h1>Place Order</h1>
Expand All @@ -19,7 +20,7 @@ templ CartOrder(products []models.Product) {
@OrdersCard(product)
}
</div>
<form hx-post="/cart/order">
<form hx-post="/cart/order" hx-target="closest form" hx-swap="afterend">
<input type="text" name="name" placeholder="Name"/>
<textarea name="address" placeholder="Adress"></textarea>
<input type="text" name="house" placeholder="House no. or House name"/>
Expand All @@ -28,7 +29,7 @@ templ CartOrder(products []models.Product) {
<input type="tel" name="phone" placeholder="Phone no."/>
<select name="payment" placeholder="Delivery method">
<option value="cod">Cash on delivery</option>
<option value="online">Credit card</option>
<option value="online">Online Payment</option>
</select>
<button type="submit" class="button-primary" style="margin-top: 2rem;">Place Order</button>
</form>
Expand Down Expand Up @@ -59,4 +60,62 @@ templ OrdersCard(product models.Product) {
<button class="button-secondary" hx-get={fmt.Sprintf("/item/%s", product.Id)} hx-push-url={fmt.Sprintf("/item/%s", product.Id)} hx-target="body" >View Product</button>
</div>
</div>
}

templ OnlinePaymentCart(order models.Order,ord map[string]interface{},key string) {
@templ.JSONScript("order-data", order)
@templ.JSONScript("ord-data", ord)
@templ.JSONScript("key-data", key)

<script id="order-data" type="application/json"></script>
<script id="ord-data" type="application/json"></script>
<script id="key-data" type="application/json"></script>

<script>
var order = JSON.parse(document.getElementById("order-data").textContent)
var ord = JSON.parse(document.getElementById("ord-data").textContent)
var key = JSON.parse(document.getElementById("key-data").textContent)
console.log(order)

var options = {
key: key,
amount: order.Total,
currency: "INR",
name: "Stitch",
description: "Cloth Shop",
"order_id": ord.id,
handler: async function (response) {
var url = "/payment-verification/" + order.id
var body = JSON.stringify({"orderId": response.razorpay_order_id, "paymentId": response.razorpay_payment_id, "razorpaySignature": response.razorpay_signature})
console.log(body)
var res = await fetch(url,{method: "POST", headers: {"Content-Type": "application/json"}, body:body})
if (res.ok) {
var json = await res.json()
alert(json)
} else {
var json = await res.json()
alert(json)
}
},
modal: {
ondismiss: async function() {
var url = "/delete-order/" + order.id
var res = await fetch(url)
if (res.ok) {
var json = await res.json()
alert(json)
}
}
},
prefil: {
name: order.Name,
contact: order.Phone
},
theme: "#ff0000"
}

var raz = new Razorpay(options)
raz.open();

</script>
}
Loading