Skip to content

Commit 3132d55

Browse files
committed
feat: add pay.ir to providers
1 parent a9e3892 commit 3132d55

File tree

9 files changed

+218
-23
lines changed

9 files changed

+218
-23
lines changed

Diff for: README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ go get -u github.com/GoFarsi/paygap
1111

1212
## Usage
1313

14-
example for zarinpal provider ([Other examples](_example))
14+
example for zarinpal provider ([Other examples](_examples))
1515

1616
```go
1717
package main
@@ -50,7 +50,7 @@ func main() {
5050

5151
- [x] zarinpal
5252
- [x] idpay
53-
- [ ] pay.ir
53+
- [x] pay.ir
5454
- [ ] yekpay
5555
- [ ] payping
5656
- [ ] rayanpay

Diff for: _example/pay/pay.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/GoFarsi/paygap/client"
7+
"github.com/GoFarsi/paygap/providers/pay"
8+
"log"
9+
)
10+
11+
func main() {
12+
ctx := context.Background()
13+
14+
p, err := pay.New(client.New(), "YOUR_API_KEY", true)
15+
if err != nil {
16+
log.Fatal(err)
17+
}
18+
19+
resp, err := p.CreateTransaction(ctx, &pay.PaymentRequest{
20+
Amount: 11000,
21+
Redirect: "http://example.com/callback",
22+
Mobile: "09151234567",
23+
FactorNumber: "xxxxx",
24+
Description: "desc test",
25+
ValidCardNumber: "1234123412341234",
26+
})
27+
28+
if err != nil {
29+
log.Fatal(err)
30+
}
31+
32+
fmt.Println(resp)
33+
34+
verifyResp, err := p.VerifyTransaction(ctx, &pay.VerifyRequest{
35+
Token: resp.Token,
36+
})
37+
38+
fmt.Println(verifyResp)
39+
}

Diff for: client/client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (c *Client) Post(ctx context.Context, apiConfig *APIConfig, headers map[str
9393

9494
if len(headers) != 0 {
9595
for k, v := range headers {
96-
req.Header.Set(k, v)
96+
req.Header.Add(k, v)
9797
}
9898
}
9999

Diff for: providers/idpay/idpay.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package idpay
22

33
import (
44
"context"
5+
"errors"
56
"github.com/GoFarsi/paygap/client"
67
"github.com/GoFarsi/paygap/status"
78
"google.golang.org/grpc/codes"
89
"net/http"
10+
"reflect"
911
)
1012

1113
const (
@@ -77,8 +79,14 @@ func (i *IdPay) TransactionList(ctx context.Context, req *TransactionListRequest
7779
}
7880

7981
func request[RQ any, RS any](ctx context.Context, i *IdPay, req RQ, baseUrl string, endpoint string) (response RS, err error) {
82+
r, ok := reflect.New(reflect.TypeOf(response).Elem()).Interface().(RS)
83+
if !ok {
84+
return response, errors.New("response type is invalid")
85+
}
86+
8087
headers := make(map[string]string)
8188
headers["X-API-KEY"] = i.apiKey
89+
headers["Content-Type"] = "application/json"
8290

8391
if i.sandbox {
8492
headers["X-SANDBOX"] = "1"
@@ -97,9 +105,9 @@ func request[RQ any, RS any](ctx context.Context, i *IdPay, req RQ, baseUrl stri
97105
return response, status.New(errResp.ErrorCode, http.StatusFailedDependency, codes.OK, errResp.ErrorMessage)
98106
}
99107

100-
if err := resp.GetJSON(response); err != nil {
108+
if err := resp.GetJSON(r); err != nil {
101109
return response, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error())
102110
}
103111

104-
return response, nil
112+
return r, nil
105113
}

Diff for: providers/idpay/models.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ type ErrorResponse struct {
2222
type PaymentRequest struct {
2323
OrderId string `validate:"required,max=50" json:"order_id"`
2424
Amount uint `validate:"required,min=1000,max=5000000000" json:"amount"`
25-
Name string `validate:"max=255" json:"name"`
26-
Phone string `validate:"max=11" json:"phone"`
25+
Name string `validate:"omitempty,max=255" json:"name"`
26+
Phone string `validate:"omitempty,max=11" json:"phone"`
2727
Mail string `validate:"email,max=255" json:"mail"`
28-
Desc string `validate:"max=255" json:"desc"`
29-
Callback string `validate:"required,max=2048" json:"callback"`
28+
Desc string `validate:"omitempty,max=255" json:"desc"`
29+
Callback string `validate:"required,max=2048,url" json:"callback"`
3030
}
3131

3232
type PaymentResponse struct {
@@ -102,11 +102,11 @@ type TransactionListRequest struct {
102102
Page uint `json:"page"`
103103
PageSize uint `json:"page_size"`
104104
Id string `json:"id"`
105-
OrderId string `validate:"max=50" json:"order_id"`
106-
Amount uint `validate:"max=5000000000,min=1000" json:"amount"`
105+
OrderId string `validate:"omitempty,max=50" json:"order_id"`
106+
Amount uint `validate:"omitempty,max=5000000000,min=1000" json:"amount"`
107107
Status []string `json:"status"`
108108
TrackId string `json:"track_id"`
109-
PaymentCardNo string `validate:"max=16" json:"payment_card_no"`
109+
PaymentCardNo string `validate:"omitempty,max=16" json:"payment_card_no"`
110110
PaymentHashedCardNo string `json:"payment_hashed_card_no"`
111111
PaymentDate struct {
112112
Min uint `json:"min"`

Diff for: providers/pay/models.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package pay
2+
3+
import "github.com/GoFarsi/paygap/client"
4+
5+
type Pay struct {
6+
client client.Transporter
7+
apiKey string
8+
9+
host string
10+
paymentEndpoint string
11+
verifyEndpoint string
12+
}
13+
14+
type ErrorResponse struct {
15+
Status int `json:"status"`
16+
ErrorCode int `json:"errorCode"`
17+
ErrorMessage string `json:"errorMessage"`
18+
}
19+
20+
type Request struct {
21+
API string `json:"api"`
22+
*PaymentRequest
23+
*VerifyRequest
24+
}
25+
26+
type PaymentRequest struct {
27+
Amount uint `json:"amount" validate:"required,min=10000"`
28+
Redirect string `json:"redirect" validate:"required,url"`
29+
Mobile string `json:"mobile,omitempty" validate:"omitempty,min=11"`
30+
FactorNumber string `json:"factorNumber,omitempty"`
31+
Description string `json:"description,omitempty" validate:"omitempty,max=255"`
32+
ValidCardNumber string `json:"validCardNumber,omitempty" validate:"omitempty,max=16"`
33+
}
34+
35+
type PaymentResponse struct {
36+
Status int `json:"status"`
37+
Token string `json:"token"`
38+
}
39+
40+
type VerifyRequest struct {
41+
Token string `json:"token" validate:"required"`
42+
}
43+
44+
type VerifyResponse struct {
45+
Status int `json:"status"`
46+
Amount string `json:"amount"`
47+
TransId string `json:"transId"`
48+
FactorNumber string `json:"factorNumber"`
49+
Mobile string `json:"mobile"`
50+
Description string `json:"description"`
51+
CardNumber string `json:"cardNumber"`
52+
Message string `json:"message"`
53+
}

Diff for: providers/pay/pay.go

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package pay
2+
3+
import (
4+
"context"
5+
"errors"
6+
"github.com/GoFarsi/paygap/client"
7+
"github.com/GoFarsi/paygap/status"
8+
"google.golang.org/grpc/codes"
9+
"net/http"
10+
"reflect"
11+
)
12+
13+
const (
14+
PAY_HOST = "https://pay.ir"
15+
16+
PAYMENT_ENDPOINT = "/pg/send"
17+
VERIFY_ENDPOINT = "/pg/verify"
18+
)
19+
20+
func New(client client.Transporter, apiKey string, sandbox bool) (*Pay, error) {
21+
if client == nil {
22+
return nil, status.ERR_CLIENT_IS_NIL
23+
}
24+
25+
pay := new(Pay)
26+
27+
pay.client = client
28+
pay.host = PAY_HOST
29+
pay.apiKey = apiKey
30+
pay.paymentEndpoint = PAYMENT_ENDPOINT
31+
pay.verifyEndpoint = VERIFY_ENDPOINT
32+
33+
if sandbox {
34+
pay.apiKey = "test"
35+
}
36+
37+
if err := client.GetValidator().Struct(pay); err != nil {
38+
return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error())
39+
}
40+
41+
return pay, nil
42+
}
43+
44+
func (p *Pay) CreateTransaction(ctx context.Context, req *PaymentRequest) (*PaymentResponse, error) {
45+
if err := p.client.GetValidator().Struct(req); err != nil {
46+
return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error())
47+
}
48+
49+
gatewayReq := new(Request)
50+
gatewayReq.API = p.apiKey
51+
gatewayReq.PaymentRequest = req
52+
53+
return request[*Request, *PaymentResponse](ctx, p, gatewayReq, p.paymentEndpoint)
54+
}
55+
56+
func (p *Pay) VerifyTransaction(ctx context.Context, req *VerifyRequest) (*VerifyResponse, error) {
57+
if err := p.client.GetValidator().Struct(req); err != nil {
58+
return nil, status.New(0, http.StatusBadRequest, codes.InvalidArgument, err.Error())
59+
}
60+
61+
gatewayReq := new(Request)
62+
gatewayReq.API = p.apiKey
63+
gatewayReq.VerifyRequest = req
64+
65+
return request[*Request, *VerifyResponse](ctx, p, gatewayReq, p.verifyEndpoint)
66+
}
67+
68+
func request[RQ any, RS any](ctx context.Context, p *Pay, req RQ, endpoint string) (response RS, err error) {
69+
r, ok := reflect.New(reflect.TypeOf(response).Elem()).Interface().(RS)
70+
if !ok {
71+
return response, errors.New("response type is invalid")
72+
}
73+
74+
errResp := new(ErrorResponse)
75+
headers := make(map[string]string)
76+
headers["Content-Type"] = "application/json"
77+
78+
resp, err := p.client.Post(ctx, &client.APIConfig{Host: p.host, Path: endpoint}, headers, req)
79+
if err != nil {
80+
return response, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error())
81+
}
82+
83+
if resp.GetHttpResponse().StatusCode != http.StatusOK {
84+
if err := resp.GetJSON(errResp); err != nil {
85+
return response, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error())
86+
}
87+
return response, status.New(errResp.ErrorCode, http.StatusFailedDependency, codes.OK, errResp.ErrorMessage)
88+
}
89+
90+
if err := resp.GetJSON(r); err != nil {
91+
return response, status.New(0, http.StatusInternalServerError, codes.Internal, err.Error())
92+
}
93+
94+
return r, nil
95+
}

Diff for: providers/zarinpal/models.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,26 @@ type Zarinpal struct {
1313
}
1414

1515
type paymentRequest struct {
16-
MerchantID string `json:"merchant_id" validate:"required"`
17-
Amount uint `json:"amount" validate:"min=5000"`
16+
merchantID string `json:"merchant_id" validate:"required"`
17+
Amount uint `json:"amount" validate:"required,min=5000"`
1818
Currency string `json:"currency"`
19-
CallBackURL string `json:"callback_url" validate:"url"`
19+
CallBackURL string `json:"callback_url" validate:"required,url"`
2020
Description string `json:"description"`
2121
MetaData map[string]interface{} `json:"metadata"`
2222
}
2323

2424
type verifyRequest struct {
25-
MerchantID string `json:"merchant_id" validate:"required"`
25+
merchantID string `json:"merchant_id" validate:"required"`
2626
Amount uint `json:"amount" validate:"min=0"`
2727
Authority string `json:"authority"`
2828
}
2929

3030
type unverifiedTransactionsRequest struct {
31-
MerchantID string `json:"merchant_id" validate:"required"`
31+
merchantID string `json:"merchant_id" validate:"required"`
3232
}
3333

3434
type floatingShareSettlementRequest struct {
35-
MerchantID string `json:"merchant_id" validate:"required"`
35+
merchantID string `json:"merchant_id" validate:"required"`
3636
Amount uint `json:"amount" validate:"min=5000"`
3737
CallBackURL string `json:"callback_url" validate:"url"`
3838
Description string `json:"description"`

Diff for: providers/zarinpal/zarinpal.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func New(client client.Transporter, merchantID string, sandbox bool) (*Zarinpal,
4848
// RequestPayment create payment request and return status code and authority
4949
func (z *Zarinpal) RequestPayment(ctx context.Context, amount uint, callBackUrl, currency, description string, metaData map[string]interface{}) (*PaymentResponse, error) {
5050
req := &paymentRequest{
51-
MerchantID: z.merchantID,
51+
merchantID: z.merchantID,
5252
Amount: amount,
5353
Currency: currency,
5454
CallBackURL: callBackUrl,
@@ -76,7 +76,7 @@ func (z *Zarinpal) RequestPayment(ctx context.Context, amount uint, callBackUrl,
7676
// VerifyPayment transaction by merchant id, amount and authority to payment provider
7777
func (z *Zarinpal) VerifyPayment(ctx context.Context, amount uint, authority string) (*VerifyResponse, error) {
7878
req := &verifyRequest{
79-
MerchantID: z.merchantID,
79+
merchantID: z.merchantID,
8080
Amount: amount,
8181
Authority: authority,
8282
}
@@ -101,7 +101,7 @@ func (z *Zarinpal) VerifyPayment(ctx context.Context, amount uint, authority str
101101
// UnverifiedTransactions get unverified transactions from provider
102102
func (z *Zarinpal) UnverifiedTransactions(ctx context.Context) (*UnverifiedTransactionsResponse, error) {
103103
req := &unverifiedTransactionsRequest{
104-
MerchantID: z.merchantID,
104+
merchantID: z.merchantID,
105105
}
106106

107107
if err := z.client.GetValidator().Struct(req); err != nil {
@@ -125,7 +125,7 @@ func (z *Zarinpal) UnverifiedTransactions(ctx context.Context) (*UnverifiedTrans
125125
// more information in https://docs.zarinpal.com/paymentGateway/setshare.html#%D8%AA%D8%B3%D9%88%DB%8C%D9%87-%D8%A7%D8%B4%D8%AA%D8%B1%D8%A7%DA%A9%DB%8C-%D8%B4%D9%86%D8%A7%D9%88%D8%B1
126126
func (z *Zarinpal) FloatingShareSettlement(ctx context.Context, amount uint, description, callbackUrl string, wages []*Wages, metaData map[string]interface{}) (*FloatingShareSettlementResponse, error) {
127127
req := &floatingShareSettlementRequest{
128-
MerchantID: z.merchantID,
128+
merchantID: z.merchantID,
129129
Amount: amount,
130130
CallBackURL: callbackUrl,
131131
Description: description,
@@ -153,7 +153,7 @@ func (z *Zarinpal) FloatingShareSettlement(ctx context.Context, amount uint, des
153153
// VerifyFloatingShareSettlement verify floating share settlement
154154
func (z *Zarinpal) VerifyFloatingShareSettlement(ctx context.Context, amount uint, authority string) (*VerifyFloatingShareSettlementResponse, error) {
155155
req := &verifyRequest{
156-
MerchantID: z.merchantID,
156+
merchantID: z.merchantID,
157157
Amount: amount,
158158
Authority: authority,
159159
}

0 commit comments

Comments
 (0)