Added support for stripe
This commit is contained in:
parent
3de5c8b0f1
commit
cefc5314f2
|
@ -37,3 +37,18 @@ CREATE TABLE IF NOT EXISTS "wspay"
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
CONSTRAINT unique_id UNIQUE ("shopping_card_id")
|
CONSTRAINT unique_id UNIQUE ("shopping_card_id")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "stripe"
|
||||||
|
(
|
||||||
|
"id" uuid NOT NULL,
|
||||||
|
"total_amount" int NOT NULL,
|
||||||
|
|
||||||
|
"lang" varchar(128) DEFAULT '',
|
||||||
|
|
||||||
|
"payment_intent_id" varchar(256) DEFAULT '',
|
||||||
|
|
||||||
|
"payment_state" varchar(256) DEFAULT '',
|
||||||
|
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
|
@ -2,7 +2,7 @@ version: '3.1'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
backend:
|
backend:
|
||||||
image: registry.bbr-dev.info/payment-poc/backend:latest
|
image: registry.s2internal.com/opgdirekt/payment-poc/backend:latest
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -26,6 +26,7 @@ require (
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
github.com/stripe/stripe-go/v72 v72.122.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -61,6 +61,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
@ -68,6 +69,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stripe/stripe-go/v72 v72.122.0 h1:eRXWqnEwGny6dneQ5BsxGzUCED5n180u8n665JHlut8=
|
||||||
|
github.com/stripe/stripe-go/v72 v72.122.0/go.mod h1:QwqJQtduHubZht9mek5sds9CtQcKFdsykV9ZepRWwo0=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
|
@ -75,14 +78,19 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
@ -92,6 +100,7 @@ google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cn
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
211
main.go
211
main.go
|
@ -6,10 +6,14 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/stripe/stripe-go/v72"
|
||||||
|
"github.com/stripe/stripe-go/v72/checkout/session"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"payment-poc/migration"
|
"payment-poc/migration"
|
||||||
|
"payment-poc/state"
|
||||||
|
stripe2 "payment-poc/stripe"
|
||||||
"payment-poc/wspay"
|
"payment-poc/wspay"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -27,8 +31,9 @@ func init() {
|
||||||
godotenv.Load()
|
godotenv.Load()
|
||||||
|
|
||||||
BackendUrl = envMustExist("BACKEND_URL")
|
BackendUrl = envMustExist("BACKEND_URL")
|
||||||
ShopId = envMustExist("SHOP_ID")
|
ShopId = envMustExist("WSPAY_SHOP_ID")
|
||||||
ShopSecret = envMustExist("SHOP_SECRET")
|
ShopSecret = envMustExist("WSPAY_SHOP_SECRET")
|
||||||
|
stripe.Key = envMustExist("STRIPE_KEY")
|
||||||
|
|
||||||
log.SetPrefix("")
|
log.SetPrefix("")
|
||||||
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
||||||
|
@ -50,22 +55,22 @@ func main() {
|
||||||
"formatCurrency": func(current int64) string {
|
"formatCurrency": func(current int64) string {
|
||||||
return fmt.Sprintf("%d,%02d", current/100, current%100)
|
return fmt.Sprintf("%d,%02d", current/100, current%100)
|
||||||
},
|
},
|
||||||
"formatState": func(state wspay.PaymentState) string {
|
"formatState": func(stt state.PaymentState) string {
|
||||||
switch state {
|
switch stt {
|
||||||
case wspay.StateCanceled:
|
case state.StateCanceled:
|
||||||
return "Otkazano"
|
return "Otkazano"
|
||||||
case wspay.StateAccepted:
|
case state.StateAccepted:
|
||||||
return "Prihvačeno"
|
return "Prihvačeno"
|
||||||
case wspay.StateError:
|
case state.StateError:
|
||||||
return "Greška"
|
return "Greška"
|
||||||
case wspay.StateInitialized:
|
case state.StateInitialized:
|
||||||
return "Inicijalna izrada"
|
return "Inicijalna izrada"
|
||||||
case wspay.StateCanceledInitialization:
|
case state.StateCanceledInitialization:
|
||||||
return "Otkazano tijekom izrade"
|
return "Otkazano tijekom izrade"
|
||||||
case wspay.StateCompleted:
|
case state.StateCompleted:
|
||||||
return "Završeno"
|
return "Završeno"
|
||||||
}
|
}
|
||||||
return "nepoznato stanje '" + string(state) + "'"
|
return "nepoznato stanje '" + string(stt) + "'"
|
||||||
},
|
},
|
||||||
"omitempty": func(value string) string {
|
"omitempty": func(value string) string {
|
||||||
if value == "" {
|
if value == "" {
|
||||||
|
@ -85,15 +90,151 @@ func main() {
|
||||||
wspayService := wspay.Service{
|
wspayService := wspay.Service{
|
||||||
DB: client,
|
DB: client,
|
||||||
}
|
}
|
||||||
|
stripeService := stripe2.Service{
|
||||||
|
DB: client,
|
||||||
|
}
|
||||||
|
|
||||||
g.LoadHTMLGlob("./templates/*.gohtml")
|
g.LoadHTMLGlob("./templates/*.gohtml")
|
||||||
|
|
||||||
g.GET("/", func(c *gin.Context) {
|
g.GET("/", func(c *gin.Context) {
|
||||||
entries, err := wspayService.FetchAll()
|
wspayEntries, _ := wspayService.FetchAll()
|
||||||
log.Printf("%v", err)
|
stripeEntries, _ := stripeService.FetchAll()
|
||||||
c.HTML(200, "index.gohtml", gin.H{"Entries": entries})
|
c.HTML(200, "index.gohtml", gin.H{"WsPay": wspayEntries, "Stripe": stripeEntries})
|
||||||
})
|
})
|
||||||
g.GET("/initial", func(c *gin.Context) {
|
|
||||||
|
g.GET("/methods", func(c *gin.Context) {
|
||||||
|
amount, err := strconv.ParseFloat(c.Query("amount"), 64)
|
||||||
|
if err != nil {
|
||||||
|
amount = 10.00
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(200, "methods.gohtml", gin.H{"Amount": amount})
|
||||||
|
})
|
||||||
|
|
||||||
|
setupWsPayEndpoints(g.Group("wspay"), wspayService)
|
||||||
|
setupStripeEndpoints(g.Group("stripe"), stripeService)
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(":5281", g))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAccounts() gin.Accounts {
|
||||||
|
auth := strings.Split(envMustExist("AUTH"), ":")
|
||||||
|
return gin.Accounts{auth[0]: auth[1]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDateTime(dateTime string) time.Time {
|
||||||
|
t, err := time.Parse("20060102150405", dateTime)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("couldn't parse response time %s: %v", dateTime, err)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupStripeEndpoints(g *gin.RouterGroup, stripeService stripe2.Service) {
|
||||||
|
g.GET("", func(c *gin.Context) {
|
||||||
|
amount, err := strconv.ParseFloat(c.Query("amount"), 64)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := stripeService.CreateEntry(int64(amount * 100))
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Created initial stripe entry (ammount=%d)", amount)
|
||||||
|
|
||||||
|
currency := string(stripe.CurrencyEUR)
|
||||||
|
productName := "Example product"
|
||||||
|
productDescription := "Simple example product"
|
||||||
|
|
||||||
|
params := &stripe.CheckoutSessionParams{
|
||||||
|
LineItems: []*stripe.CheckoutSessionLineItemParams{
|
||||||
|
{
|
||||||
|
PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{
|
||||||
|
Currency: ¤cy,
|
||||||
|
ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{
|
||||||
|
Name: &productName,
|
||||||
|
Description: &productDescription,
|
||||||
|
},
|
||||||
|
UnitAmount: &entry.TotalAmount,
|
||||||
|
},
|
||||||
|
Quantity: stripe.Int64(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mode: stripe.String(string(stripe.CheckoutSessionModePayment)),
|
||||||
|
PaymentIntentData: &stripe.CheckoutSessionPaymentIntentDataParams{
|
||||||
|
CaptureMethod: stripe.String("manual"),
|
||||||
|
},
|
||||||
|
SuccessURL: stripe.String(BackendUrl + "/stripe/success?token=" + entry.Id.String()),
|
||||||
|
CancelURL: stripe.String(BackendUrl + "/stripe/cancel?token=" + entry.Id.String()),
|
||||||
|
}
|
||||||
|
result, err := session.New(params)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
entry.PaymentIntentId = result.PaymentIntent.ID
|
||||||
|
stripeService.Update(entry)
|
||||||
|
|
||||||
|
c.Redirect(http.StatusSeeOther, result.URL)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.GET("success", func(c *gin.Context) {
|
||||||
|
id := uuid.MustParse(c.Query("token"))
|
||||||
|
|
||||||
|
log.Printf("Received success response for stripe payment %s", id)
|
||||||
|
entry, err := stripeService.FetchById(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Couldn't find payment info for stripe payment %s", id)
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.State = state.StateAccepted
|
||||||
|
|
||||||
|
if err := stripeService.Update(entry); err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Stripe payment %s received correctly, returning redirect", id)
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, "/")
|
||||||
|
})
|
||||||
|
g.GET("error", func(c *gin.Context) {
|
||||||
|
id := uuid.MustParse(c.Query("token"))
|
||||||
|
|
||||||
|
log.Printf("Received error response for stripe payment %s", id)
|
||||||
|
entry, err := stripeService.FetchById(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Couldn't find payment info for stripe payment %s", id)
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.State = state.StateError
|
||||||
|
|
||||||
|
if err := stripeService.Update(entry); err != nil {
|
||||||
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Stripe payment %s received correctly, returning redirect", id)
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, "/")
|
||||||
|
})
|
||||||
|
g.GET("info/:id", func(c *gin.Context) {
|
||||||
|
id := uuid.MustParse(c.Param("id"))
|
||||||
|
entry, err := stripeService.FetchById(id)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusNotFound, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.HTML(200, "stripe_info.gohtml", gin.H{"Entry": entry})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupWsPayEndpoints(g *gin.RouterGroup, wspayService wspay.Service) {
|
||||||
|
g.GET("", func(c *gin.Context) {
|
||||||
amount, err := strconv.ParseFloat(c.Query("amount"), 64)
|
amount, err := strconv.ParseFloat(c.Query("amount"), 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err)
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
@ -113,15 +254,15 @@ func main() {
|
||||||
ShoppingCartID: entry.ShoppingCartID,
|
ShoppingCartID: entry.ShoppingCartID,
|
||||||
Version: "2.0",
|
Version: "2.0",
|
||||||
TotalAmount: entry.TotalAmount,
|
TotalAmount: entry.TotalAmount,
|
||||||
ReturnURL: BackendUrl + "/initial/success",
|
ReturnURL: BackendUrl + "/wspay/success",
|
||||||
ReturnErrorURL: BackendUrl + "/initial/error",
|
ReturnErrorURL: BackendUrl + "/wspay/error",
|
||||||
CancelURL: BackendUrl + "/initial/cancel",
|
CancelURL: BackendUrl + "/wspay/cancel",
|
||||||
Signature: wspay.CalculateFormSignature(ShopId, ShopSecret, entry.ShoppingCartID, entry.TotalAmount),
|
Signature: wspay.CalculateFormSignature(ShopId, ShopSecret, entry.ShoppingCartID, entry.TotalAmount),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.HTML(200, "initial.gohtml", gin.H{"Action": wspay.AuthorisationForm, "Form": form})
|
c.HTML(200, "wspay.gohtml", gin.H{"Action": wspay.AuthorisationForm, "Form": form})
|
||||||
})
|
})
|
||||||
g.GET("/initial/success", func(c *gin.Context) {
|
g.GET("success", func(c *gin.Context) {
|
||||||
response := wspay.WsPayFormReturn{}
|
response := wspay.WsPayFormReturn{}
|
||||||
if err := c.ShouldBind(&response); err != nil {
|
if err := c.ShouldBind(&response); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
@ -161,7 +302,7 @@ func main() {
|
||||||
entry.ApprovalCode = response.ApprovalCode
|
entry.ApprovalCode = response.ApprovalCode
|
||||||
entry.ErrorMessage = response.ErrorMessage
|
entry.ErrorMessage = response.ErrorMessage
|
||||||
|
|
||||||
entry.State = wspay.StateAccepted
|
entry.State = state.StateAccepted
|
||||||
|
|
||||||
if err := wspayService.Update(entry); err != nil {
|
if err := wspayService.Update(entry); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
@ -176,10 +317,7 @@ func main() {
|
||||||
c.Redirect(http.StatusTemporaryRedirect, "/")
|
c.Redirect(http.StatusTemporaryRedirect, "/")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
g.GET("/iframe", func(c *gin.Context) {
|
g.GET("error", func(c *gin.Context) {
|
||||||
c.HTML(200, "iframe_handler.gohtml", gin.H{})
|
|
||||||
})
|
|
||||||
g.GET("/initial/error", func(c *gin.Context) {
|
|
||||||
response := wspay.WsPayFormError{}
|
response := wspay.WsPayFormError{}
|
||||||
if err := c.ShouldBind(&response); err != nil {
|
if err := c.ShouldBind(&response); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
@ -212,7 +350,7 @@ func main() {
|
||||||
entry.ErrorMessage = response.ErrorMessage
|
entry.ErrorMessage = response.ErrorMessage
|
||||||
entry.ErrorCodes = response.ErrorCodes
|
entry.ErrorCodes = response.ErrorCodes
|
||||||
|
|
||||||
entry.State = wspay.StateError
|
entry.State = state.StateError
|
||||||
|
|
||||||
if err := wspayService.Update(entry); err != nil {
|
if err := wspayService.Update(entry); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
@ -234,9 +372,9 @@ func main() {
|
||||||
c.AbortWithError(http.StatusNotFound, err)
|
c.AbortWithError(http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.HTML(200, "info.gohtml", gin.H{"Entry": entry})
|
c.HTML(200, "wspay_info.gohtml", gin.H{"Entry": entry})
|
||||||
})
|
})
|
||||||
g.GET("/initial/cancel", func(c *gin.Context) {
|
g.GET("cancel", func(c *gin.Context) {
|
||||||
response := wspay.WsPayFormCancel{}
|
response := wspay.WsPayFormCancel{}
|
||||||
if err := c.ShouldBind(&response); err != nil {
|
if err := c.ShouldBind(&response); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
@ -249,7 +387,7 @@ func main() {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entry.State = wspay.StateCanceledInitialization
|
entry.State = state.StateCanceledInitialization
|
||||||
|
|
||||||
if err := wspayService.Update(entry); err != nil {
|
if err := wspayService.Update(entry); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
@ -264,19 +402,4 @@ func main() {
|
||||||
c.Redirect(http.StatusTemporaryRedirect, "/")
|
c.Redirect(http.StatusTemporaryRedirect, "/")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(":5281", g))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAccounts() gin.Accounts {
|
|
||||||
auth := strings.Split(envMustExist("AUTH"), ":")
|
|
||||||
return gin.Accounts{auth[0]: auth[1]}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseDateTime(dateTime string) time.Time {
|
|
||||||
t, err := time.Parse("20060102150405", dateTime)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("couldn't parse response time %s: %v", dateTime, err)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
}
|
||||||
|
|
8
makefile
8
makefile
|
@ -17,10 +17,10 @@ docker-dev:
|
||||||
|
|
||||||
|
|
||||||
docker-prod:
|
docker-prod:
|
||||||
docker image build -t registry.bbr-dev.info/payment-poc/backend:$(VERSION) .
|
docker image build -t registry.s2internal.com/opgdirekt/payment-poc/backend:$(VERSION) .
|
||||||
docker tag registry.bbr-dev.info/payment-poc/backend:$(VERSION) registry.bbr-dev.info/payment-poc/backend:latest
|
docker tag registry.s2internal.com/opgdirekt/payment-poc/backend:$(VERSION) registry.s2internal.com/opgdirekt/payment-poc/backend:latest
|
||||||
docker image push registry.bbr-dev.info/payment-poc/backend:$(VERSION)
|
docker image push registry.s2internal.com/opgdirekt/payment-poc/backend:$(VERSION)
|
||||||
docker image push registry.bbr-dev.info/payment-poc/backend:latest
|
docker image push registry.s2internal.com/opgdirekt/payment-poc/backend:latest
|
||||||
|
|
||||||
release:
|
release:
|
||||||
git tag $(VERSION)
|
git tag $(VERSION)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
type PaymentState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// initial state
|
||||||
|
StateInitialized PaymentState = "initialized"
|
||||||
|
|
||||||
|
// state on response
|
||||||
|
StateAccepted PaymentState = "accepted"
|
||||||
|
StateError PaymentState = "error"
|
||||||
|
StateCanceledInitialization PaymentState = "canceled_initialization"
|
||||||
|
|
||||||
|
// state after confirmation
|
||||||
|
StateCompleted PaymentState = "completed"
|
||||||
|
StateVoided PaymentState = "voided"
|
||||||
|
StateCanceled PaymentState = "canceled"
|
||||||
|
)
|
|
@ -0,0 +1,16 @@
|
||||||
|
package stripe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"payment-poc/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StripeDb struct {
|
||||||
|
Id uuid.UUID `db:"id"`
|
||||||
|
TotalAmount int64 `db:"total_amount"`
|
||||||
|
Lang string `db:"lang"`
|
||||||
|
|
||||||
|
PaymentIntentId string `db:"payment_intent_id"`
|
||||||
|
|
||||||
|
State state.PaymentState `db:"payment_state"`
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package stripe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"payment-poc/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
DB *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateEntry(totalAmount int64) (StripeDb, error) {
|
||||||
|
id := uuid.Must(uuid.NewRandom())
|
||||||
|
entry := StripeDb{
|
||||||
|
Id: id,
|
||||||
|
TotalAmount: totalAmount,
|
||||||
|
State: state.StateInitialized,
|
||||||
|
}
|
||||||
|
_, err := s.DB.Exec(`INSERT INTO "stripe" ("id", "total_amount", "payment_state") VALUES ($1, $2, $3)`,
|
||||||
|
&entry.Id, &entry.TotalAmount, &entry.State,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return StripeDb{}, err
|
||||||
|
}
|
||||||
|
return s.FetchById(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) FetchAll() ([]StripeDb, error) {
|
||||||
|
var entries []StripeDb
|
||||||
|
err := s.DB.Select(&entries, `SELECT * FROM "stripe"`)
|
||||||
|
return entries, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) FetchById(id uuid.UUID) (StripeDb, error) {
|
||||||
|
entry := StripeDb{}
|
||||||
|
err := s.DB.Get(&entry, `SELECT * FROM "stripe" WHERE "id" = $1`, id)
|
||||||
|
return entry, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Update(entry StripeDb) error {
|
||||||
|
_, err := s.DB.Exec(`UPDATE "stripe" set "payment_intent_id" = $2, "payment_state" = $3 WHERE "id" = $1`,
|
||||||
|
&entry.Id, &entry.PaymentIntentId, &entry.State,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -13,6 +13,9 @@
|
||||||
tr > td:nth-child(2) {
|
tr > td:nth-child(2) {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
tr > th:nth-child(2) {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
td, th {
|
td, th {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +27,7 @@
|
||||||
<body class="container">
|
<body class="container">
|
||||||
<h2>Novo plačanje</h2>
|
<h2>Novo plačanje</h2>
|
||||||
|
|
||||||
<form method="get" action="/initial">
|
<form method="get" action="/methods">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="amount">Vrijednost</label>
|
<label class="form-label" for="amount">Vrijednost</label>
|
||||||
<input class="form-control" id="amount" required name="amount" type="number" step="0.01" min="0">
|
<input class="form-control" id="amount" required name="amount" type="number" step="0.01" min="0">
|
||||||
|
@ -33,7 +36,7 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Plačanja</h2>
|
<h2>WsPay</h2>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -43,9 +46,29 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{range .Entries}}
|
{{range .WsPay}}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="link-primary" href="/info/{{.Id}}">{{.Id}}</a></td>
|
<td><a class="link-primary" href="/wspay/info/{{.Id}}">{{.Id}}</a></td>
|
||||||
|
<td>{{formatCurrency .TotalAmount}}</td>
|
||||||
|
<td>{{formatState .State}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Stripe</h2>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<th>Vrijednost</th>
|
||||||
|
<th>Stanje</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .Stripe}}
|
||||||
|
<tr>
|
||||||
|
<td><a class="link-primary" href="/stripe/info/{{.Id}}">{{.Id}}</a></td>
|
||||||
<td>{{formatCurrency .TotalAmount}}</td>
|
<td>{{formatCurrency .TotalAmount}}</td>
|
||||||
<td>{{formatState .State}}</td>
|
<td>{{formatState .State}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Index</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
|
||||||
|
<style>
|
||||||
|
th {text-align: left}
|
||||||
|
tr > td:nth-child(2) {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="container">
|
||||||
|
<h2>Izaberi metodu plačanja</h2>
|
||||||
|
<a class="btn btn-success" href="/wspay?amount={{.Amount}}">WsPay</a>
|
||||||
|
<a class="btn btn-success" href="/stripe?amount={{.Amount}}">Stripe</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Info</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
|
||||||
|
<style>
|
||||||
|
th {text-align: left}
|
||||||
|
h2 {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="container">
|
||||||
|
<h2>Plačanje {{.Entry.Id}}</h2>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<tr><th>Id: </th><td>{{.Entry.Id}}</td></tr>
|
||||||
|
<tr><th>Ukupna vrijednost: </th><td>{{formatCurrency .Entry.TotalAmount}}</td></tr>
|
||||||
|
<tr><th>Jezik: </th><td>{{omitempty .Entry.Lang}}</td></tr>
|
||||||
|
<tr><th>Stanje: </th><td>{{formatState .Entry.State}}</td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -2,26 +2,10 @@ package wspay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"payment-poc/state"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PaymentState string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// initial state
|
|
||||||
StateInitialized PaymentState = "initialized"
|
|
||||||
|
|
||||||
// state on response
|
|
||||||
StateAccepted PaymentState = "accepted"
|
|
||||||
StateError PaymentState = "error"
|
|
||||||
StateCanceledInitialization PaymentState = "canceled_initialization"
|
|
||||||
|
|
||||||
// state after confirmation
|
|
||||||
StateCompleted PaymentState = "completed"
|
|
||||||
StateVoided PaymentState = "voided"
|
|
||||||
StateCanceled PaymentState = "canceled"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WsPayDb struct {
|
type WsPayDb struct {
|
||||||
Id uuid.UUID `db:"id"`
|
Id uuid.UUID `db:"id"`
|
||||||
ShopID string `db:"shop_id"`
|
ShopID string `db:"shop_id"`
|
||||||
|
@ -53,5 +37,5 @@ type WsPayDb struct {
|
||||||
ErrorMessage string `db:"error_message"`
|
ErrorMessage string `db:"error_message"`
|
||||||
ErrorCodes string `db:"error_codes"`
|
ErrorCodes string `db:"error_codes"`
|
||||||
|
|
||||||
State PaymentState `db:"payment_state"`
|
State state.PaymentState `db:"payment_state"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
"payment-poc/state"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ func (s *Service) CreateEntry(shopId string, totalAmount int64) (WsPayDb, error)
|
||||||
ShopID: shopId,
|
ShopID: shopId,
|
||||||
ShoppingCartID: id.String(),
|
ShoppingCartID: id.String(),
|
||||||
TotalAmount: totalAmount,
|
TotalAmount: totalAmount,
|
||||||
State: StateInitialized,
|
State: state.StateInitialized,
|
||||||
}
|
}
|
||||||
_, err := s.DB.Exec(`INSERT INTO "wspay" ("id", "shop_id", "shopping_card_id", "total_amount", "payment_state") VALUES ($1, $2, $3, $4, $5)`,
|
_, err := s.DB.Exec(`INSERT INTO "wspay" ("id", "shop_id", "shopping_card_id", "total_amount", "payment_state") VALUES ($1, $2, $3, $4, $5)`,
|
||||||
&entry.Id, &entry.ShopID, &entry.ShoppingCartID, &entry.TotalAmount, &entry.State,
|
&entry.Id, &entry.ShopID, &entry.ShoppingCartID, &entry.TotalAmount, &entry.State,
|
||||||
|
|
Loading…
Reference in New Issue