Skip to content

Commit b90d2ee

Browse files
Merge pull request #102 from anderson-rsantos/feature/orders_3ds
[Feature] Orders 3DS
2 parents cf976f1 + 608551b commit b90d2ee

File tree

8 files changed

+199
-29
lines changed

8 files changed

+199
-29
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ go.work
1919

2020
# IDE
2121
.idea
22-
.vscode
22+
.vscode
23+
24+
# Local tooling/temp
25+
tmp-mcp-installer/

examples/apis/cardtoken/create/main.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ func main() {
2222
request := cardtoken.Request{
2323
SiteID: "{{SITE_ID}}",
2424
CardNumber: "{{CARD_NUMBER}}",
25-
ExpirationMonth: "11",
26-
ExpirationYear: "2025",
27-
SecurityCode: "123",
25+
ExpirationMonth: "{{EXPIRATION_MONTH}}",
26+
ExpirationYear: "{{EXPIRATION_YEAR}}",
27+
SecurityCode: "{{SECURITY_CODE}}",
2828
Cardholder: &cardtoken.CardholderRequest{
2929
Identification: &cardtoken.IdentificationRequest{
3030
Type: "CPF",
31-
Number: "{{CPF_NUMBER}}",
31+
Number: "{{NUMBER_CPF}}",
3232
},
33-
Name: "{{PAYMENT_METHOD}}",
33+
Name: "{{NAME}}",
3434
},
3535
}
3636

examples/apis/order/create/main.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,25 @@ func main() {
1818

1919
client := order.NewClient(c)
2020
request := order.Request{
21-
Type: "online",
22-
TotalAmount: "1000.00",
23-
ExternalReference: "ext_ref_1234",
24-
Currency: "BRL",
21+
Type: "{{TYPE}}",
22+
TotalAmount: "{{TOTAL_AMOUNT}}",
23+
ExternalReference: "{{EXTERNAL_REFERENCE}}",
24+
Currency: "BRL",
2525
Transactions: &order.TransactionRequest{
2626
Payments: []order.PaymentRequest{
2727
{
28-
Amount: "1000.00",
28+
Amount: "{{AMOUNT}}",
2929
PaymentMethod: &order.PaymentMethodRequest{
30-
ID: "master",
30+
ID: "{{PAYMENT_METHOD_ID}}",
3131
Token: "{{CARD_TOKEN}}",
32-
Type: "credit_card",
32+
Type: "{{TYPE}}",
3333
Installments: 1,
3434
},
3535
},
3636
},
3737
},
3838
Payer: &order.PayerRequest{
39-
Email: "{{PAYER_EMAIL}}",
39+
Email: "{{EMAIL}}",
4040
},
4141
}
4242

@@ -45,5 +45,6 @@ func main() {
4545
fmt.Println(err)
4646
return
4747
}
48+
4849
fmt.Println(resource)
4950
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/mercadopago/sdk-go/pkg/config"
8+
"github.com/mercadopago/sdk-go/pkg/order"
9+
)
10+
11+
func main() {
12+
accessToken := "{{ACCESS_TOKEN}}"
13+
c, err := config.New(accessToken)
14+
if err != nil {
15+
fmt.Println(err)
16+
return
17+
}
18+
19+
client := order.NewClient(c)
20+
request := order.Request{
21+
Type: "{{TYPE}}",
22+
TotalAmount: "{{TOTAL_AMOUNT}}",
23+
ExternalReference: "{{EXTERNAL_REFERENCE}}",
24+
Transactions: &order.TransactionRequest{
25+
Payments: []order.PaymentRequest{
26+
{
27+
Amount: "{{AMOUNT}}",
28+
PaymentMethod: &order.PaymentMethodRequest{
29+
ID: "{{PAYMENT_METHOD_ID}}",
30+
Token: "{{CARD_TOKEN}}",
31+
Type: "{{TYPE}}",
32+
Installments: 1,
33+
},
34+
},
35+
},
36+
},
37+
Payer: &order.PayerRequest{
38+
Email: "{{EMAIL}}",
39+
},
40+
Config: &order.ConfigRequest{
41+
Online: &order.OnlineConfigRequest{
42+
TransactionSecurity: &order.TransactionSecurityRequest{
43+
Validation: "always",
44+
LiabilityShift: "preferred",
45+
},
46+
},
47+
},
48+
}
49+
50+
resource, err := client.Create(context.Background(), request)
51+
if err != nil {
52+
fmt.Println(err)
53+
return
54+
}
55+
56+
fmt.Println(resource)
57+
}
58+
59+

pkg/order/client_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package order
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"io"
78
"net/http"
@@ -1160,3 +1161,43 @@ func TestNewClient(t *testing.T) {
11601161
})
11611162
}
11621163
}
1164+
1165+
func TestCreate_TransactionSecurity_Simple(t *testing.T) {
1166+
reqBody := Request{
1167+
Config: &ConfigRequest{
1168+
Online: &OnlineConfigRequest{
1169+
TransactionSecurity: &TransactionSecurityRequest{
1170+
Validation: "always",
1171+
LiabilityShift: "preferred",
1172+
},
1173+
},
1174+
},
1175+
}
1176+
1177+
cfg := &config.Config{
1178+
Requester: &httpclient.Mock{
1179+
DoMock: func(req *http.Request) (*http.Response, error) {
1180+
var got struct {
1181+
Config *ConfigRequest `json:"config,omitempty"`
1182+
}
1183+
if err := json.NewDecoder(req.Body).Decode(&got); err != nil {
1184+
return nil, err
1185+
}
1186+
expected := struct {
1187+
Config *ConfigRequest `json:"config,omitempty"`
1188+
}{
1189+
Config: reqBody.Config,
1190+
}
1191+
if !reflect.DeepEqual(got, expected) {
1192+
return nil, fmt.Errorf("body mismatch: got=%+v want=%+v", got, expected)
1193+
}
1194+
return &http.Response{Body: io.NopCloser(strings.NewReader(`{"id":"ord","status":"processing"}`))}, nil
1195+
},
1196+
},
1197+
}
1198+
1199+
c := &client{cfg: cfg}
1200+
if _, err := c.Create(context.Background(), reqBody); err != nil {
1201+
t.Fatalf("Create() error: %v", err)
1202+
}
1203+
}

pkg/order/request.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,14 @@ type OnlineConfigRequest struct {
228228
FailureURL string `json:"failure_url,omitempty"`
229229
AutoReturnURL string `json:"auto_return_url,omitempty"`
230230
DifferentialPricing *DifferentialPricingRequest `json:"differential_pricing,omitempty"`
231+
TransactionSecurity *TransactionSecurityRequest `json:"transaction_security,omitempty"`
231232
}
232233

233234
type DifferentialPricingRequest struct {
234235
ID int `json:"id,omitempty"`
235236
}
237+
238+
type TransactionSecurityRequest struct {
239+
Validation string `json:"validation,omitempty"`
240+
LiabilityShift string `json:"liability_shift,omitempty"`
241+
}

pkg/order/response.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,32 @@ type PaymentResponse struct {
5353
}
5454

5555
type PaymentMethodResponse struct {
56-
ID string `json:"id,omitempty"`
57-
CardID string `json:"card_id,omitempty"`
58-
Type string `json:"type,omitempty"`
59-
Token string `json:"token,omitempty"`
60-
StatementDescriptor string `json:"statement_descriptor,omitempty"`
61-
Installments int `json:"installments,omitempty"`
62-
TicketURL string `json:"ticket_url,omitempty"`
63-
BarcodeContent string `json:"barcode_content,omitempty"`
64-
Reference string `json:"reference,omitempty"`
65-
ReferenceID string `json:"reference_id,omitempty"`
66-
VerificationCode string `json:"verification_code,omitempty"`
67-
FinancialInstitution string `json:"financial_institution,omitempty"`
68-
QrCode string `json:"qr_code,omitempty"`
69-
QrCodeBase64 string `json:"qr_code_base64,omitempty"`
70-
DigitableLine string `json:"digitable_line,omitempty"`
56+
ID string `json:"id,omitempty"`
57+
CardID string `json:"card_id,omitempty"`
58+
Type string `json:"type,omitempty"`
59+
Token string `json:"token,omitempty"`
60+
StatementDescriptor string `json:"statement_descriptor,omitempty"`
61+
Installments int `json:"installments,omitempty"`
62+
TicketURL string `json:"ticket_url,omitempty"`
63+
BarcodeContent string `json:"barcode_content,omitempty"`
64+
Reference string `json:"reference,omitempty"`
65+
ReferenceID string `json:"reference_id,omitempty"`
66+
VerificationCode string `json:"verification_code,omitempty"`
67+
FinancialInstitution string `json:"financial_institution,omitempty"`
68+
QrCode string `json:"qr_code,omitempty"`
69+
QrCodeBase64 string `json:"qr_code_base64,omitempty"`
70+
DigitableLine string `json:"digitable_line,omitempty"`
71+
TransactionSecurity *TransactionSecurityResponse `json:"transaction_security,omitempty"`
72+
}
73+
74+
// TransactionSecurityResponse represents 3DS-related information returned by the API
75+
// for a payment method when a challenge may be required.
76+
type TransactionSecurityResponse struct {
77+
URL string `json:"url,omitempty"`
78+
Validation string `json:"validation,omitempty"`
79+
LiabilityShift string `json:"liability_shift,omitempty"`
80+
Type string `json:"type,omitempty"`
81+
Status string `json:"status,omitempty"`
7182
}
7283

7384
type AutomaticPaymentResponse struct {

test/integration/order/order_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,52 @@ func TestRefundOrder(t *testing.T) {
486486
}
487487
})
488488
}
489+
490+
func TestOrderTransactionSecurity(t *testing.T) {
491+
t.Run("should_create_order_with_transaction_security", func(t *testing.T) {
492+
ctx := context.Background()
493+
token, err := test.GenerateCardToken(ctx, cardTokenClient)
494+
if err != nil {
495+
t.Error("fail to generate card token", err)
496+
}
497+
498+
request := order.Request{
499+
Type: "online",
500+
ProcessingMode: "automatic",
501+
TotalAmount: "100.00",
502+
ExternalReference: fmt.Sprintf("ext_ref_ts_%s", uuid.New().String()[:7]),
503+
Payer: &order.PayerRequest{
504+
Email: fmt.Sprintf("test_user_%s@testuser.com", uuid.New().String()[:7]),
505+
},
506+
Config: &order.ConfigRequest{
507+
Online: &order.OnlineConfigRequest{
508+
TransactionSecurity: &order.TransactionSecurityRequest{
509+
Validation: "always",
510+
LiabilityShift: "preferred",
511+
},
512+
},
513+
},
514+
Transactions: &order.TransactionRequest{
515+
Payments: []order.PaymentRequest{
516+
{
517+
Amount: "100.00",
518+
PaymentMethod: &order.PaymentMethodRequest{
519+
ID: "master",
520+
Token: token,
521+
Type: "credit_card",
522+
Installments: 1,
523+
},
524+
},
525+
},
526+
},
527+
}
528+
529+
resource, err := orderClient.Create(ctx, request)
530+
if resource == nil || resource.ID == "" {
531+
t.Error("order can't be nil")
532+
}
533+
if err != nil {
534+
t.Errorf(err.Error())
535+
}
536+
})
537+
}

0 commit comments

Comments
 (0)