Added payment update action

This commit is contained in:
Borna Rajković committed 2023-07-31 09:21:54 +02:00
1 parent b6203d8a03
commit fe6f3b6672
12 files changed
+420 -105

No files matched your search

+102 -16
View File
@@ -9,6 +9,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"io"
"log"
"net/http"
"payment-poc/database"
"payment-poc/state"
@@ -16,22 +17,67 @@ import (
)
type Service struct {
Provider *database.PaymentEntryProvider
ShopId string
ShopSecret string
BackendUrl string
}
func (s *Service) CreatePaymentUrl(amount int64) (string, error) {
entry, err := s.Provider.CreateEntry(database.PaymentEntry{
Gateway: state.GatewayWsPay,
State: state.StateInitialized,
TotalAmount: amount,
})
if err != nil {
return "", err
func (s *Service) UpdatePayment(entry database.PaymentEntry) (updatedEntry database.PaymentEntry, err error) {
var request = StatusCheckRequest{
Version: "2.0",
ShopId: s.ShopId,
ShoppingCartId: entry.Id.String(),
Signature: CalculateStatusCheckSignature(s.ShopId, s.ShopSecret, entry.Id.String()),
}
return "/wspay/initialize/" + entry.Id.String(), nil
httpResponse, err := createRequest(
"POST",
"https://test.wspay.biz/api/services/statusCheck",
map[string]string{"content-type": "application/json"},
toJson(request),
)
if err != nil {
return database.PaymentEntry{}, err
}
var response StatusCheckResponse
err = readResponse(httpResponse, &response)
if err != nil {
return database.PaymentEntry{}, err
}
if CompareStatusCheckReturnSignature(response.Signature, s.ShopId, s.ShopSecret, response.ActionSuccess, response.ApprovalCode, entry.Id.String()) != nil {
entry.Amount = &response.Amount
newState := determineState(response)
if entry.State != newState && newState != "" {
log.Printf("Updated state for %s: %s -> %s", entry.Id.String(), entry.State, newState)
entry.State = newState
}
entry.State = state.StateCompleted
} else {
return database.PaymentEntry{}, errors.New("invalid signature")
}
return entry, nil
}
func determineState(response StatusCheckResponse) state.PaymentState {
if response.Completed == "1" {
return state.StateCompleted
} else if response.Voided == "1" {
return state.StateVoided
} else if response.Refunded == "1" {
return state.StateVoided
} else if response.Authorized == "1" {
return state.StateAccepted
} else {
return state.StateInitialized
}
}
func (s *Service) CreatePaymentUrl(entry database.PaymentEntry) (database.PaymentEntry, string, error) {
return entry, "/wspay/initialize/" + entry.Id.String(), nil
}
func (s *Service) CompleteTransaction(entry database.PaymentEntry, amount int64) (database.PaymentEntry, error) {
@@ -127,12 +173,12 @@ func (s *Service) InitializePayment(entry database.PaymentEntry) Form {
return form
}
func (s *Service) HandleSuccessResponse(c *gin.Context) (string, error) {
func (s *Service) HandleSuccessResponse(c *gin.Context, provider *database.PaymentEntryProvider) (string, error) {
response := FormReturn{}
if err := c.ShouldBind(&response); err != nil {
return "", err
}
entry, err := s.Provider.FetchById(uuid.MustParse(response.ShoppingCartID))
entry, err := provider.FetchById(uuid.MustParse(response.ShoppingCartID))
if err != nil {
return "", err
}
@@ -148,19 +194,19 @@ func (s *Service) HandleSuccessResponse(c *gin.Context) (string, error) {
entry.ApprovalCode = &response.ApprovalCode
entry.State = state.StateAccepted
if _, err := s.Provider.UpdateEntry(entry); err != nil {
if _, err := provider.UpdateEntry(entry); err != nil {
return "", err
}
return "/entries/" + entry.Id.String(), nil
}
func (s *Service) HandleErrorResponse(c *gin.Context, paymentState state.PaymentState) (string, error) {
func (s *Service) HandleErrorResponse(c *gin.Context, provider *database.PaymentEntryProvider, paymentState state.PaymentState) (string, error) {
response := FormError{}
if err := c.ShouldBind(&response); err != nil {
return "", err
}
entry, err := s.Provider.FetchById(uuid.MustParse(response.ShoppingCartID))
entry, err := provider.FetchById(uuid.MustParse(response.ShoppingCartID))
if err != nil {
return "", err
}
@@ -176,7 +222,7 @@ func (s *Service) HandleErrorResponse(c *gin.Context, paymentState state.Payment
entry.Error = &response.ErrorMessage
entry.State = paymentState
if _, err := s.Provider.UpdateEntry(entry); err != nil {
if _, err := provider.UpdateEntry(entry); err != nil {
return "", err
}
@@ -268,6 +314,46 @@ func CompareCompletionReturnSignature(signature string, shopId string, secret st
}
}
func CompareStatusCheckReturnSignature(signature string, shopId string, secret string, actionSuccess string, approvalCode string, cartId string) error {
/**
Represents a signature created from string formatted from following values in a following order using
SHA512 algorithm:
ShopID
SecretKey
ActionSuccess
ApprovalCode
SecretKey
ShopID
ApprovalCode
WsPayOrderId
*/
calculatedSignature := shopId + secret + actionSuccess + approvalCode + secret + shopId + approvalCode + cartId
hash := sha512.New()
hash.Write([]byte(calculatedSignature))
if hex.EncodeToString(hash.Sum(nil)) == signature {
return nil
} else {
return errors.New("signature mismatch")
}
}
func CalculateStatusCheckSignature(shopId string, secret string, cartId string) string {
/**
Represents a signature created from string formatted from following values in a following order using
SHA512 algorithm:
ShopID
SecretKey
ShoppingCartID
SecretKey
ShopID
ShoppingCartID
*/
signature := shopId + secret + cartId + secret + shopId + cartId
hash := sha512.New()
hash.Write([]byte(signature))
return hex.EncodeToString(hash.Sum(nil))
}
func readResponse[T any](httpResponse *http.Response, response T) error {
if httpResponse.StatusCode == http.StatusOK {
content, err := io.ReadAll(httpResponse.Body)
+6 -6
View File
@@ -130,14 +130,14 @@ type StatusCheckResponse struct {
ApprovalCode string
ShopID string
ShoppingCartID string
Amount string
Amount int64
CurrencyCode string
ActionSuccess string
Success string // deprecated
Authorized int
Completed int
Voided int
Refunded int
Authorized string
Completed string
Voided string
Refunded string
PaymentPlan string
Partner string
OnSite int
@@ -151,7 +151,7 @@ type StatusCheckResponse struct {
CustomerCountry string
CustomerPhone string
CustomerEmail string
TransactionDateTime string //yyyymmddHHMMss
TransactionDateTime string // yyyymmddHHMMss
IsLessThan30DaysFromTransaction bool
CanBeCompleted bool
CanBeVoided bool