diff --git a/main.go b/main.go index 92262e2..bf4fdbc 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,10 @@ package main import ( + "bytes" "embed" + "encoding/json" + "errors" "fmt" "github.com/gin-gonic/gin" "github.com/google/uuid" @@ -10,6 +13,7 @@ import ( "github.com/stripe/stripe-go/v72/checkout/session" "github.com/stripe/stripe-go/v72/paymentintent" "html/template" + "io" "log" "net/http" "payment-poc/migration" @@ -39,6 +43,7 @@ func init() { godotenv.Load() BackendUrl = envMustExist("BACKEND_URL") + WsPayShopId = envMustExist("WSPAY_SHOP_ID") WsPayShopSecret = envMustExist("WSPAY_SHOP_SECRET") @@ -493,6 +498,124 @@ func setupWsPayEndpoints(g *gin.RouterGroup, wspayService wspay.Service) { c.HTML(200, "wspay.gohtml", gin.H{"Action": wspay.AuthorisationForm, "Form": form}) }) + g.POST("complete/:id", func(c *gin.Context) { + id := uuid.MustParse(c.Param("id")) + amount, err := strconv.ParseFloat(c.PostForm("amount"), 64) + if err != nil { + c.AbortWithError(http.StatusBadRequest, err) + return + } + entry, err := wspayService.FetchById(id) + if err != nil { + c.AbortWithError(http.StatusNotFound, err) + return + } + if int64(amount*100) > entry.TotalAmount || int64(amount*100) < 1 { + c.AbortWithError(http.StatusBadRequest, err) + return + } + if entry.State == state.StateAccepted { + var request = wspay.WsPayCompletionRequest{ + Version: "2.0", + WsPayOrderId: entry.ShoppingCartID, + ShopId: entry.ShopID, + ApprovalCode: entry.ApprovalCode, + STAN: entry.STAN, + Amount: int64(amount * 100), + Signature: wspay.CalculateCompletionSignature(WsPayShopId, WsPayShopSecret, entry.ShoppingCartID, entry.STAN, entry.ApprovalCode, int64(amount*100)), + } + + content, _ := json.Marshal(&request) + response, err := http.Post("https://test.wspay.biz/api/services/completion", "application/json", bytes.NewBuffer(content)) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + if response.StatusCode == http.StatusOK { + transactionResponse := wspay.WsPayCompletionResponse{} + content, err := io.ReadAll(response.Body) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + if err := json.Unmarshal(content, &transactionResponse); err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } else { + log.Printf("Received transaction response: success=%s, errorMessage=%s, approvalCode=%s", + transactionResponse.ActionSuccess, transactionResponse.ErrorMessage, transactionResponse.ApprovalCode, + ) + if wspay.CompareCompletionReturnSignature(transactionResponse.Signature, WsPayShopId, WsPayShopSecret, entry.ShoppingCartID, entry.STAN, transactionResponse.ActionSuccess, transactionResponse.ApprovalCode) != nil { + entry.TotalAmount = int64(amount * 100) + entry.State = state.StateCompleted + wspayService.Update(entry) + } else { + c.AbortWithError(http.StatusInternalServerError, errors.New("received invalid signature")) + return + } + } + } else { + c.AbortWithError(http.StatusInternalServerError, errors.New("received wrong status, expected 200 received "+strconv.FormatInt(int64(response.StatusCode), 10))) + return + } + } + + c.Redirect(http.StatusSeeOther, "/wspay/info/"+id.String()) + }) + g.POST("cancel/:id", func(c *gin.Context) { + id := uuid.MustParse(c.Param("id")) + entry, err := wspayService.FetchById(id) + if err != nil { + c.AbortWithError(http.StatusNotFound, err) + return + } + if entry.State == state.StateAccepted { + var request = wspay.WsPayCompletionRequest{ + Version: "2.0", + WsPayOrderId: entry.ShoppingCartID, + ShopId: entry.ShopID, + ApprovalCode: entry.ApprovalCode, + STAN: entry.STAN, + Amount: entry.TotalAmount, + Signature: wspay.CalculateCompletionSignature(WsPayShopId, WsPayShopSecret, entry.ShoppingCartID, entry.STAN, entry.ApprovalCode, entry.TotalAmount), + } + + content, _ := json.Marshal(&request) + response, err := http.Post("https://test.wspay.biz/api/services/void", "application/json", bytes.NewBuffer(content)) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + if response.StatusCode == http.StatusOK { + transactionResponse := wspay.WsPayCompletionResponse{} + content, err := io.ReadAll(response.Body) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + if err := json.Unmarshal(content, &transactionResponse); err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } else { + log.Printf("Received transaction response: success=%s, errorMessage=%s, approvalCode=%s", + transactionResponse.ActionSuccess, transactionResponse.ErrorMessage, transactionResponse.ApprovalCode, + ) + if wspay.CompareCompletionReturnSignature(transactionResponse.Signature, WsPayShopId, WsPayShopSecret, entry.ShoppingCartID, entry.STAN, transactionResponse.ActionSuccess, transactionResponse.ApprovalCode) != nil { + entry.State = state.StateCanceled + wspayService.Update(entry) + } else { + c.AbortWithError(http.StatusInternalServerError, errors.New("received invalid signature")) + return + } + } + } else { + c.AbortWithError(http.StatusInternalServerError, errors.New("received wrong status, expected 200 received "+strconv.FormatInt(int64(response.StatusCode), 10))) + return + } + } + + c.Redirect(http.StatusSeeOther, "/wspay/info/"+id.String()) + }) g.GET("success", func(c *gin.Context) { response := wspay.WsPayFormReturn{} if err := c.ShouldBind(&response); err != nil { diff --git a/templates/wspay_info.gohtml b/templates/wspay_info.gohtml index c6d3bdb..f20f233 100644 --- a/templates/wspay_info.gohtml +++ b/templates/wspay_info.gohtml @@ -45,5 +45,18 @@