Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for wallets service #11

Merged
merged 3 commits into from
Feb 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 17 additions & 41 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type TokenResponse struct {
// later use.
func (c Client) Authenticate() (*TokenResponse, error) {
uri := c.tokenEndpoint()
auth := authBody(c.Config)
auth := AuthBody(c.Config)

grant := []byte("grant_type=client_credentials")
req, _ := http.NewRequest("POST", uri, bytes.NewBuffer(grant))
Expand Down Expand Up @@ -58,39 +58,46 @@ func (c Client) Authenticate() (*TokenResponse, error) {
// AuthToken returns the token value
func (c Client) AuthToken() string {
c.lock.RLock()
defer c.lock.RUnlock()

t := c.tokenValue.value

c.lock.RUnlock()
return t
}

// SetToken sets the token value and the expiration time of the token.
func (c Client) SetToken(tokenValue string, expires time.Time) {
func (c Client) SetToken(value string, expires time.Time) {
c.lock.Lock()
defer c.lock.Unlock()

c.tokenValue = token{
value: tokenValue,
expires: expires,
}
c.tokenValue.value = value
c.tokenValue.expires = expires

c.lock.Unlock()
}

// HasAuthExpired returns true if the expiry time of the token has passed and false
// otherwise.
func (c Client) HasAuthExpired() bool {
c.lock.RLock()
defer c.lock.RUnlock()

expires := c.tokenValue.expires

c.lock.RUnlock()

now := time.Now()
return now.After(expires)
}

func authBody(c Config) string {
func AuthBody(c Config) string {
auth := fmt.Sprintf("%s:%s", c.ClientID, c.ClientSecret)
return base64.StdEncoding.EncodeToString([]byte(auth))
}

func BasicAuth(c Config) string {
auth := fmt.Sprintf("%s:%s", c.MerchantID, c.APIKey)
return base64.StdEncoding.EncodeToString([]byte(auth))
}

func (c Client) tokenEndpoint() string {
return fmt.Sprintf("%s/%s", c.authUri(), "/connect/token")
}
Expand All @@ -101,34 +108,3 @@ func (c Client) authUri() string {
}
return "https://accounts.vivapayments.com"
}

type OAuthRoundTripper struct {
tokenValue token
transport http.RoundTripper
}

func (c OAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
authType := pickAuth(req)
fmt.Println(authType)

resp, err := c.transport.RoundTrip(req)
if resp != nil && err == nil {
return resp, nil
}
return nil, err
}

type AuthType int
const (
oauth AuthType = iota
basicAuth
)

func pickAuth(r *http.Request) AuthType {
switch r.RequestURI {
case "/":
return oauth
default:
return basicAuth
}
}
32 changes: 24 additions & 8 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,36 @@ import (
)

func main() {
clientID := ""
clientSecret := ""
client := vivawallet.New(clientID, clientSecret, true)
clientID := "yjp82d6eub7hva6y9usesqtuzd8ambj914odu50n49jz3.apps.vivapayments.com"
clientSecret := "ODX4vwQVmeYo373814yYf2p6Vq85yR"
merchantID := "393969b6-c18e-4770-ba9a-2838c2beafee"
apiKey := "YZ}z>_"
client := vivawallet.New(clientID, clientSecret, merchantID, apiKey, true)

token, err := client.Authenticate()
if err != nil {
fmt.Printf("Error: %s", err.Error())
fmt.Printf("Error: %s\n", err.Error())
return
}
fmt.Printf("Token: %s\n", token.AccessToken)
fmt.Printf("Token: %s\n\n", token.AccessToken)

req := vivawallet.CheckoutOrderRequest{
req := vivawallet.CheckoutOrder{
Amount: 1000,
}
op, _ := client.CreateOrderPayment(req)
fmt.Printf("OrderPayment: %d\n", op.OrderCode)
op, err2 := client.CreateOrderPayment(req)
if err2 != nil {
fmt.Printf("err: %s\n", err2.Error())
} else {
fmt.Printf("OrderPayment: %d\n", op.OrderCode)
}

wallets, err3 := client.GetWallets()
if err3 != nil {
fmt.Printf("err: %s\n", err3.Error())
} else {
for _, w := range wallets {
fmt.Printf("Wallet: %v\n", w)
}
}

}
18 changes: 9 additions & 9 deletions order_payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"net/http"
)

type CheckoutOrderRequest struct {
type CheckoutOrder struct {
Amount int64 `json:"amount"`
CustomerTransactions string `json:"customerTrns"`
CustomerTransactions string `json:"customerTrns,omitempty"`
Customer struct {
Email string `json:"email,omitempty"`
FullName string `json:"fullName,omitempty"`
Expand All @@ -32,14 +32,14 @@ type CheckoutOrderRequest struct {
CardTokens []string `json:"cardTokens,omitempty"`
}

type CheckoutResponse struct {
type CheckoutOrderResponse struct {
OrderCode int64 `json:"orderCode"`
}

// CreateOrderPayment creates a new order payment and returns the `orderCode`.
func (c Client) CreateOrderPayment(order CheckoutOrderRequest) (*CheckoutResponse, error) {
uri := checkoutEndpoint(c.Config)
data, err := json.Marshal(order)
func (c Client) CreateOrderPayment(payload CheckoutOrder) (*CheckoutOrderResponse, error) {
uri := checkoutOrderUri(c.Config)
data, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("failed to parse order %s", err)
}
Expand Down Expand Up @@ -68,14 +68,14 @@ func (c Client) CreateOrderPayment(order CheckoutOrderRequest) (*CheckoutRespons
return nil, bodyErr
}

response := &CheckoutResponse{}
response := &CheckoutOrderResponse{}
if jsonErr := json.Unmarshal(body, response); jsonErr != nil {
return nil, jsonErr
}

return response, nil
}

func checkoutEndpoint(c Config) string {
return fmt.Sprintf("%s/%s", ApiUri(c), "checkout/v2/orders")
func checkoutOrderUri(c Config) string {
return fmt.Sprintf("%s/checkout/v2/orders", ApiUri(c))
}
20 changes: 10 additions & 10 deletions transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"time"
)

type Transaction struct {
type TransactionResponse struct {
Email string `json:"email"`
Amount int `json:"amount"`
OrderCode string `json:"orderCode"`
Expand All @@ -31,7 +31,7 @@ type Transaction struct {
DigitalWalletID int `json:"digitalWalletId"`
}

func (c Client) GetTransaction(trxID string) (*Transaction, error) {
func (c Client) GetTransaction(trxID string) (*TransactionResponse, error) {
uri := getTransactionUri(c.Config, trxID)

// TODO: use RoundTripper to avoid rewriting this
Expand Down Expand Up @@ -59,33 +59,33 @@ func (c Client) GetTransaction(trxID string) (*Transaction, error) {
return nil, bodyErr
}

trx := &Transaction{}
trx := &TransactionResponse{}
if jsonErr := json.Unmarshal(body, trx); jsonErr != nil {
return nil, jsonErr
}
return trx, nil
}

func getTransactionUri(c Config, trxID string) string {
return fmt.Sprintf("%s/%s/%s", ApiUri(c), "checkout/v2/transactions", trxID)
return fmt.Sprintf("%s/checkout/v2/transactions/%s", ApiUri(c), trxID)
}

type CreateCardToken struct {
TransactionID string `json:"transactionId"`
}

type CardToken struct {
type CardTokenResponse struct {
Token string `json:"token"`
}

func (c Client) CreateCardToken(payload CreateCardToken) (*CardToken, error) {
func (c Client) CreateCardToken(payload CreateCardToken) (*CardTokenResponse, error) {
// TODO: use RoundTripper to avoid rewriting this
if c.HasAuthExpired() {
_, authErr := c.Authenticate()
return nil, fmt.Errorf("authentication error %s", authErr)
}

uri := getCreateCardToken(c.Config)
uri := getCreateCardTokenUri(c.Config)
data, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("failed to parse CreateCardToken %s", err)
Expand All @@ -110,13 +110,13 @@ func (c Client) CreateCardToken(payload CreateCardToken) (*CardToken, error) {
return nil, bodyErr
}

cardToken := &CardToken{}
cardToken := &CardTokenResponse{}
if jsonErr := json.Unmarshal(body, cardToken); jsonErr != nil {
return nil, jsonErr
}
return cardToken, nil
}

func getCreateCardToken(c Config) string {
return fmt.Sprintf("%s/%s", ApiUri(c), "acquiring/v1/cards/tokens")
func getCreateCardTokenUri(c Config) string {
return fmt.Sprintf("%s/acquiring/v1/cards/tokens", ApiUri(c))
}
19 changes: 15 additions & 4 deletions viva_wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ type Config struct {
Demo bool
ClientID string
ClientSecret string
MerchantID string
APIKey string
}

type token struct {
Expand All @@ -20,8 +22,8 @@ type token struct {
type Client struct {
Config Config
HTTPClient *http.Client
lock *sync.RWMutex
tokenValue token
lock sync.RWMutex
tokenValue *token
}

// defaultHTTPTimeout is the default timeout on the http.Client used by the library.
Expand All @@ -32,14 +34,17 @@ var httpClient = &http.Client{
}

// New creates a new viva client
func New(clientID string, clientSecret string, demo bool) *Client {
func New(clientID string, clientSecret string, merchantID string, apiKey string, demo bool) *Client {
return &Client{
Config: Config{
Demo: demo,
ClientID: clientID,
ClientSecret: clientSecret,
MerchantID: merchantID,
APIKey: apiKey,
},
HTTPClient: httpClient,
tokenValue: &token{},
}
}

Expand All @@ -51,7 +56,13 @@ func ApiUri(c Config) string {
return "https://api.vivapayments.com"
}

func AppUri(c Config) string {
if isDemo(c) {
return "https://demo.vivapayments.com"
}
return "https://www.vivapayments.com"
}

func isDemo(c Config) bool {
return c.Demo
}

Loading