From 13a0832be961e8d8cffbd258cf375dd3debd18c1 Mon Sep 17 00:00:00 2001 From: Mahdi Azadnar Date: Sat, 18 Feb 2023 21:43:42 +0330 Subject: [PATCH] feat/add-vandar-payment-gateway --- README.md | 4 +- _example/vandar/main.go | 42 ++++++++++++ providers/vandar/models.go | 73 ++++++++++++++++++++ providers/vandar/vandar.go | 136 +++++++++++++++++++++++++++++++++++++ 4 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 _example/vandar/main.go create mode 100644 providers/vandar/models.go create mode 100644 providers/vandar/vandar.go diff --git a/README.md b/README.md index bf6eb57..703e199 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,10 @@ package main import ( "context" "fmt" + "log" + "github.com/GoFarsi/paygap/client" "github.com/GoFarsi/paygap/providers/zarinpal" - "log" ) func main() { @@ -52,6 +53,7 @@ func main() { - [x] idpay - [x] pay.ir - [x] payping +- [x] vandar.io - [ ] rayanpay - [ ] nextpay - [ ] mellat diff --git a/_example/vandar/main.go b/_example/vandar/main.go new file mode 100644 index 0000000..3478a02 --- /dev/null +++ b/_example/vandar/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "log" + + "github.com/GoFarsi/paygap/client" + "github.com/GoFarsi/paygap/providers/vandar" +) + +func main() { + c := client.New() + v, err := vandar.New(c, "4924fc5aeca14bfdaa0d44162baf4fb7ee19d706") + if err != nil { + log.Fatal(err) + } + + resp, err := v.RequestPayment(context.Background(), 10000, "http://vandagateway.local:8081/callback", + "09353917307", "", "", "", "") + if err != nil { + log.Printf("%+v\n", err) + } + + //make a break point and Go to payment page :=https://ipg.vandar.io/v3/{token} and token is resp.Token + + //get transaction detail + detailResp, detailErr := v.TransactionDetail(context.Background(), resp.Token) + if detailErr != nil { + log.Fatal(err) + } + + log.Printf("%+v\n", detailResp) + + //and verify Transction + verifyResp, verifyErr := v.TransactionDetail(context.Background(), resp.Token) + if verifyErr != nil { + log.Fatal(err) + } + + log.Printf("%+v\n", verifyResp) + +} diff --git a/providers/vandar/models.go b/providers/vandar/models.go new file mode 100644 index 0000000..ad8a64b --- /dev/null +++ b/providers/vandar/models.go @@ -0,0 +1,73 @@ +package vandar + +import "github.com/GoFarsi/paygap/client" + +type Vandar struct { + client client.Transporter + APIKey string `validate:"required"` + + baseUrl string + requestEndpoint string + redirectEndpoint string + transactionDetailEndpoint string + verifyEndpoint string +} + +type paymentRequest struct { + ApiKey string `json:"api_key"` + Amount int `json:"amount" validate:"required,min=1000"` + CallBackURL string `json:"callback_url" validate:"required,url"` + MobileNumber string `json:"mobile_number"` + FactorNumber string `json:"factorNumber"` + Description string `json:"description"` + NationalCode string `json:"national_code"` + ValidCardNumber string `json:"valid_card_number"` +} + +type PaymentResponse struct { + Status int `json:"status"` + Token string `json:"token"` + Errors []string `json:"errors"` +} + +type verifyRequest struct { + APIKey string `json:"api_key"` + Token string `json:"token"` +} + +type VerifyResponse struct { + Status int `json:"status"` + Errors []string `json:"errors"` + Amount string `json:"amount"` + RealAmount int `json:"realAmount"` + Wage string `json:"wage"` + TransID int64 `json:"transId"` + FactorNumber string `json:"factorNumber"` + Mobile string `json:"mobile"` + Description string `json:"description"` + CardNumber string `json:"cardNumber"` + PaymentDate string `json:"paymentDate"` + Cid string `json:"cid"` + Message string `json:"message"` +} + +type transactionDetailRequest struct { + APIKey string `json:"api_key"` + Token string `json:"token"` +} + +type TransactionDetailResponse struct { + Status *int `json:"status"` + Amount *string `json:"amount"` + TransId *int `json:"transId"` + RefNumber *string `json:"refnumber"` + TrackingCode *string `json:"trackingCode"` + FactorNumber *string `json:"factorNumber"` + Mobile *string `json:"mobile"` + Description *string `json:"description"` + CardNumber *string `json:"cardNumber"` + CID *string `json:"CID"` + CreatedAt *string `json:"createdAt"` + PaymentDate *string `json:"paymentDate"` + Code *int `json:"code"` +} diff --git a/providers/vandar/vandar.go b/providers/vandar/vandar.go new file mode 100644 index 0000000..8b10cac --- /dev/null +++ b/providers/vandar/vandar.go @@ -0,0 +1,136 @@ +package vandar + +import ( + "context" + "net/http" + + "github.com/GoFarsi/paygap/client" + "github.com/GoFarsi/paygap/status" + "google.golang.org/grpc/codes" +) + +const API_VERSION = "3" + +const ( + VANDAR_HOST = "https://ipg.vandar.io/api" +) + +const ( + VANDAR_REQUEST_API_ENDPOINT = "/v3/send" + VANDAR_REDIRECT_API_ENDPOINT = "/v3/" + VANDAR_VERIFY_API_ENDPOINT = "/v3/verify" + VANDAR_TRANSACTION_DETAIL_API_END_POINT = "/v3/transaction" +) + +// New create vandar provider object for user factory request methods +func New(client client.Transporter, ApiKey string) (*Vandar, error) { + if client == nil { + return nil, status.ERR_CLIENT_IS_NIL + } + + vandar := &Vandar{ + client: client, + APIKey: ApiKey, + baseUrl: VANDAR_HOST, + requestEndpoint: VANDAR_REQUEST_API_ENDPOINT, + redirectEndpoint: VANDAR_REDIRECT_API_ENDPOINT, + verifyEndpoint: VANDAR_VERIFY_API_ENDPOINT, + transactionDetailEndpoint: VANDAR_TRANSACTION_DETAIL_API_END_POINT, + } + + if err := client.GetValidator().Struct(vandar); err != nil { + return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error()) + } + + return vandar, nil +} + +// RequestPayment create payment request and return status code and authority +// document of field https://vandarpay.github.io/docs/ipg/#step-1 +func (v *Vandar) RequestPayment(ctx context.Context, amount int, callBackUrl, mobileNumber, factorNumber, nationalCode, validCardNumber, description string) (*PaymentResponse, error) { + req := paymentRequest{ + ApiKey: v.APIKey, + Amount: amount, + CallBackURL: callBackUrl, + MobileNumber: mobileNumber, + FactorNumber: factorNumber, + NationalCode: nationalCode, + ValidCardNumber: validCardNumber, + Description: description, + } + + if err := v.client.GetValidator().Struct(req); err != nil { + return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error()) + } + + headers := make(map[string]string) + headers["Content-Type"] = "application/json" + + response := &PaymentResponse{} + resp, err := v.client.Post(ctx, &client.APIConfig{Host: v.baseUrl, Path: v.requestEndpoint, Headers: headers}, req) + if err != nil { + return nil, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error()) + } + + if err := resp.GetJSON(response); err != nil { + return nil, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error()) + } + + return response, nil +} + +// VerifyPayment transaction by merchant id, amount and authority to payment provider +// doc https://vandarpay.github.io/docs/ipg/#step-4 +func (v *Vandar) VerifyPayment(ctx context.Context, token string) (*VerifyResponse, error) { + req := &verifyRequest{ + APIKey: v.APIKey, + Token: token, + } + + if err := v.client.GetValidator().Struct(req); err != nil { + return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error()) + } + + headers := make(map[string]string) + headers["Content-Type"] = "application/json" + + response := &VerifyResponse{} + resp, err := v.client.Post(ctx, &client.APIConfig{Host: v.baseUrl, Path: v.verifyEndpoint, Headers: headers}, req) + if err != nil { + return nil, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error()) + } + + if err := resp.GetJSON(response); err != nil { + return nil, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error()) + } + + return response, nil +} + +// TransactionDetail Transaction Detail get Transaction status +// doc https://vandarpay.github.io/docs/ipg/#step-3 +func (v *Vandar) TransactionDetail(ctx context.Context, token string) (*TransactionDetailResponse, error) { + req := &transactionDetailRequest{ + APIKey: v.APIKey, + Token: token, + } + + if err := v.client.GetValidator().Struct(req); err != nil { + return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error()) + } + + headers := make(map[string]string) + headers["Content-Type"] = "application/json" + + response := &TransactionDetailResponse{} + resp, err := v.client.Post(ctx, &client.APIConfig{Host: v.baseUrl, Path: v.transactionDetailEndpoint, Headers: headers}, req) + if err != nil { + return nil, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error()) + } + + if err := resp.GetJSON(response); err != nil { + return nil, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error()) + } + + return response, nil +}