Skip to content

Commit

Permalink
Merge pull request #7 from mercadopago/feature/card-token
Browse files Browse the repository at this point in the history
Feature/card token
  • Loading branch information
meliguilhermefernandes authored Feb 9, 2024
2 parents 537493b + 442601a commit c9c34e8
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 0 deletions.
1 change: 1 addition & 0 deletions .testcoverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ exclude:
paths:
- ^pkg/internal
- ^pkg/config
- ^pkg/cardtoken/mock.go
43 changes: 43 additions & 0 deletions examples/apis/cardtoken/create/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package create

import (
"context"
"fmt"

"github.com/mercadopago/sdk-go/pkg/cardtoken"
"github.com/mercadopago/sdk-go/pkg/config"
)

func main() {
accessToken := "{{ACCESS_TOKEN}}"

cfg, err := config.New(accessToken)
if err != nil {
fmt.Println(err)
return
}

client := cardtoken.NewClient(cfg)

var req = cardtoken.Request{
SiteID: "{{SITE_ID}}",
CardNumber: "{{CARD_NUMBER}}",
ExpirationMonth: "11",
ExpirationYear: "2025",
SecurityCode: "123",
Cardholder: &cardtoken.Cardholder{
Identification: &cardtoken.Identification{
Type: "CPF",
Number: "{{CPF_NUMBER}}",
},
Name: "{{PAYMENT_METHOD}}",
},
}

result, err := client.Create(context.Background(), req)
if err != nil {
return
}

fmt.Println(result)
}
33 changes: 33 additions & 0 deletions pkg/cardtoken/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cardtoken

import (
"context"

"github.com/mercadopago/sdk-go/pkg/config"
"github.com/mercadopago/sdk-go/pkg/internal/httpclient"
)

const url = "https://api.mercadopago.com/v1/card_tokens"

// Client contains the method to interact with the card token API.
type Client interface {
// Create create a card token.
// It is a post request to the endpoint: https://api.mercadopago.com/v1/card_tokens
Create(ctx context.Context, request Request) (*Response, error)
}

type client struct {
cfg *config.Config
}

func NewClient(c *config.Config) Client {
return &client{cfg: c}
}

func (c *client) Create(ctx context.Context, request Request) (*Response, error) {
res, err := httpclient.Post[Response](ctx, c.cfg, url, request)
if err != nil {
return nil, err
}
return res, nil
}
95 changes: 95 additions & 0 deletions pkg/cardtoken/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package cardtoken

import (
"context"
"fmt"
"io"
"net/http"
"os"
"reflect"
"strings"
"testing"

"github.com/mercadopago/sdk-go/pkg/config"
"github.com/mercadopago/sdk-go/pkg/internal/httpclient"
)

var (
cardTokenResponseJSON, _ = os.Open("../../resources/mocks/cardtoken/response.json")
cardTokenResponse, _ = io.ReadAll(cardTokenResponseJSON)
)

func TestCreate(t *testing.T) {
type fields struct {
cfg *config.Config
}
type args struct {
ctx context.Context
request Request
}
tests := []struct {
name string
fields fields
args args
want *Response
wantErr string
}{
{
name: "should_create_card_token",
fields: fields{
cfg: &config.Config{
Requester: &httpclient.Mock{
DoMock: func(req *http.Request) (*http.Response, error) {
stringReader := strings.NewReader(string(cardTokenResponse))
stringReadCloser := io.NopCloser(stringReader)
return &http.Response{
Body: stringReadCloser,
}, nil
},
},
},
},
args: args{
ctx: context.Background(),
},
want: mockCardToken(),
wantErr: "",
},
{
name: "should_fail_create_card_token",
fields: fields{
cfg: &config.Config{
Requester: &httpclient.Mock{
DoMock: func(req *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("some error")
},
},
},
},
args: args{
ctx: context.Background(),
},
want: nil,
wantErr: "transport level error: some error",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &client{
cfg: tt.fields.cfg,
}
got, err := c.Create(tt.args.ctx, tt.args.request)
gotErr := ""
if err != nil {
gotErr = err.Error()
}

if gotErr != tt.wantErr {
t.Errorf("card token client.Create() error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("card token client.Create() = %v, want %v", got, tt.want)
}
})
}
}
52 changes: 52 additions & 0 deletions pkg/cardtoken/mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cardtoken

import (
"time"
)

func mockCardToken() *Response {
return &Response{
ID: "3d40b34eb41a6d0923e5bc545927c2e9",
FirstSixDigits: "503143",
ExpirationMonth: 11,
ExpirationYear: 2025,
LastFourDigits: "6351",
Cardholder: CardholderResponse{
Identification: IdentificationResponse{
Number: "70383868084",
Type: "CPF",
},
Name: "MASTER TEST",
},
Status: "active",
DateCreated: parseDate("2024-02-08T09:05:42.725-04:00"),
DateLastUpdated: parseDate("2024-02-08T09:05:42.725-04:00"),
DateDue: parseDate("2024-02-16T09:05:42.725-04:00"),
LuhnValidation: true,
LiveMode: false,
CardNumberLength: 16,
SecurityCodeLength: 3,
}
}

func MockCardTokenRequest() Request {
return Request{
SiteID: "Teste",
CardNumber: "5031433215406351",
ExpirationMonth: "11",
ExpirationYear: "2025",
SecurityCode: "123",
Cardholder: &Cardholder{
Identification: &Identification{
Type: "CPF",
Number: "70383868084",
},
Name: "MASTER TEST",
},
}
}

func parseDate(s string) *time.Time {
d, _ := time.Parse(time.RFC3339, s)
return &d
}
20 changes: 20 additions & 0 deletions pkg/cardtoken/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cardtoken

type Request struct {
SiteID string `json:"site_id,omitempty"`
CardNumber string `json:"card_number,omitempty"`
ExpirationYear string `json:"expiration_year,omitempty"`
ExpirationMonth string `json:"expiration_month,omitempty"`
SecurityCode string `json:"security_code,omitempty"`
Cardholder *Cardholder `json:"cardholder,omitempty"`
}

type Cardholder struct {
Identification *Identification `json:"identification,omitempty"`
Name string `json:"name,omitempty"`
}

type Identification struct {
Number string `json:"number,omitempty"`
Type string `json:"type,omitempty"`
}
31 changes: 31 additions & 0 deletions pkg/cardtoken/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cardtoken

import "time"

type Response struct {
ID string `json:"id"`
FirstSixDigits string `json:"first_six_digits"`
LastFourDigits string `json:"last_four_digits"`
Status string `json:"status"`
LuhnValidation bool `json:"luhn_validation"`
LiveMode bool `json:"live_mode"`
RequireEsc bool `json:"require_esc"`
ExpirationMonth int `json:"expiration_month"`
ExpirationYear int `json:"expiration_year"`
CardNumberLength int `json:"card_number_length"`
SecurityCodeLength int `json:"security_code_length"`
DateCreated *time.Time `json:"date_created"`
DateLastUpdated *time.Time `json:"date_last_updated"`
DateDue *time.Time `json:"date_due"`
Cardholder CardholderResponse `json:"cardholder"`
}

type CardholderResponse struct {
Identification IdentificationResponse `json:"identification,omitempty"`
Name string `json:"name"`
}

type IdentificationResponse struct {
Number string `json:"number"`
Type string `json:"type"`
}
23 changes: 23 additions & 0 deletions resources/mocks/cardtoken/response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"id": "3d40b34eb41a6d0923e5bc545927c2e9",
"first_six_digits": "503143",
"expiration_month": 11,
"expiration_year": 2025,
"last_four_digits": "6351",
"cardholder": {
"identification": {
"number": "70383868084",
"type": "CPF"
},
"name": "MASTER TEST"
},
"status": "active",
"date_created": "2024-02-08T09:05:42.725-04:00",
"date_last_updated": "2024-02-08T09:05:42.725-04:00",
"date_due": "2024-02-16T09:05:42.725-04:00",
"luhn_validation": true,
"live_mode": false,
"require_esc": false,
"card_number_length": 16,
"security_code_length": 3
}
29 changes: 29 additions & 0 deletions test/integration/cardtoken/cardtoken_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cardtoken

import (
"context"
"os"
"testing"

"github.com/mercadopago/sdk-go/pkg/cardtoken"
"github.com/mercadopago/sdk-go/pkg/config"
)

func TestCardToken(t *testing.T) {
t.Run("should_create_card_token", func(t *testing.T) {
cfg, err := config.New(os.Getenv("ACCESS_TOKEN"))
if err != nil {
t.Fatal(err)
}

client := cardtoken.NewClient(cfg)
res, err := client.Create(context.Background(), cardtoken.MockCardTokenRequest())

if res == nil {
t.Error("res can't be nil")
}
if err != nil {
t.Errorf(err.Error())
}
})
}

0 comments on commit c9c34e8

Please sign in to comment.