Skip to content

Commit 83554ee

Browse files
Fix account holder payment context source. Partial Authorization (#120)
* Add partial authorization in payment request * Fix account holder payment context source
1 parent 0bfe87e commit 83554ee

File tree

6 files changed

+223
-47
lines changed

6 files changed

+223
-47
lines changed

common/common.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,12 @@ type (
182182
AccountHolder struct {
183183
Type AccountHolderType `json:"type,omitempty"`
184184
Title string `json:"title,omitempty"`
185+
FullName string `json:"full_name,omitempty"`
185186
FirstName string `json:"first_name,omitempty"`
186187
MiddleName string `json:"middle_name,omitempty"`
187188
LastName string `json:"last_name,omitempty"`
189+
Email string `json:"email,omitempty"`
190+
Gender string `json:"gender,omitempty"`
188191
CompanyName string `json:"company_name,omitempty"`
189192
TaxId string `json:"tax_id,omitempty"`
190193
DateOfBirth string `json:"date_of_birth,omitempty"`
@@ -193,8 +196,6 @@ type (
193196
BillingAddress *Address `json:"billing_address,omitempty"`
194197
Phone *Phone `json:"phone,omitempty"`
195198
Identification *AccountHolderIdentification `json:"identification,omitempty"`
196-
Email string `json:"email,omitempty"`
197-
Gender string `json:"gender,omitempty"`
198199
}
199200
)
200201

payments/nas/payments.go

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -77,42 +77,47 @@ type (
7777
IssuingCountry common.Country `json:"issuing_country,omitempty"`
7878
DateOfExpiry string `json:"date_of_expiry,omitempty"`
7979
}
80+
81+
PartialAuthorization struct {
82+
Enabled bool `json:"enabled,omitempty"`
83+
}
8084
)
8185

8286
// Request
8387
type (
8488
PaymentRequest struct {
85-
PaymentContextId string `json:"payment_context_id,omitempty"`
86-
Source payments.PaymentSource `json:"source,omitempty"`
87-
Amount int64 `json:"amount,omitempty"`
88-
Currency common.Currency `json:"currency,omitempty"`
89-
PaymentType payments.PaymentType `json:"payment_type,omitempty"`
90-
MerchantInitiated bool `json:"merchant_initiated"`
91-
Reference string `json:"reference,omitempty"`
92-
Description string `json:"description,omitempty"`
93-
AuthorizationType AuthorizationType `json:"authorization_type,omitempty"`
94-
Capture bool `json:"capture"`
95-
CaptureOn *time.Time `json:"capture_on,omitempty"`
96-
Customer *common.CustomerRequest `json:"customer,omitempty"`
97-
BillingDescriptor *payments.BillingDescriptor `json:"billing_descriptor,omitempty"`
98-
ShippingDetails *payments.ShippingDetails `json:"shipping,omitempty"`
99-
Segment *payments.PaymentSegment `json:"segment,omitempty"`
100-
ThreeDsRequest *payments.ThreeDsRequest `json:"3ds,omitempty"`
101-
PreviousPaymentId string `json:"previous_payment_id,omitempty"`
102-
ProcessingChannelId string `json:"processing_channel_id,omitempty"`
103-
Risk *payments.RiskRequest `json:"risk,omitempty"`
104-
SuccessUrl string `json:"success_url,omitempty"`
105-
FailureUrl string `json:"failure_url,omitempty"`
106-
PaymentIp string `json:"payment_ip,omitempty"`
107-
Sender Sender `json:"sender,omitempty"`
108-
Recipient *payments.PaymentRecipient `json:"recipient,omitempty"`
109-
Marketplace *common.MarketplaceData `json:"marketplace,omitempty"`
110-
AmountAllocations []common.AmountAllocations `json:"amount_allocations,omitempty"`
111-
Processing *payments.ProcessingSettings `json:"processing,omitempty"`
112-
Items []payments.Product `json:"items,omitempty"`
113-
Retry *payments.PaymentRetryRequest `json:"retry,omitempty"`
114-
Metadata map[string]interface{} `json:"metadata,omitempty"`
115-
Instruction *PaymentInstruction `json:"instruction,omitempty"`
89+
PaymentContextId string `json:"payment_context_id,omitempty"`
90+
Source payments.PaymentSource `json:"source,omitempty"`
91+
Amount int64 `json:"amount,omitempty"`
92+
Currency common.Currency `json:"currency,omitempty"`
93+
PaymentType payments.PaymentType `json:"payment_type,omitempty"`
94+
MerchantInitiated bool `json:"merchant_initiated"`
95+
Reference string `json:"reference,omitempty"`
96+
Description string `json:"description,omitempty"`
97+
AuthorizationType AuthorizationType `json:"authorization_type,omitempty"`
98+
PartialAuthorization *PartialAuthorization `json:"partial_authorization,omitempty"`
99+
Capture bool `json:"capture"`
100+
CaptureOn *time.Time `json:"capture_on,omitempty"`
101+
Customer *common.CustomerRequest `json:"customer,omitempty"`
102+
BillingDescriptor *payments.BillingDescriptor `json:"billing_descriptor,omitempty"`
103+
ShippingDetails *payments.ShippingDetails `json:"shipping,omitempty"`
104+
Segment *payments.PaymentSegment `json:"segment,omitempty"`
105+
ThreeDsRequest *payments.ThreeDsRequest `json:"3ds,omitempty"`
106+
PreviousPaymentId string `json:"previous_payment_id,omitempty"`
107+
ProcessingChannelId string `json:"processing_channel_id,omitempty"`
108+
Risk *payments.RiskRequest `json:"risk,omitempty"`
109+
SuccessUrl string `json:"success_url,omitempty"`
110+
FailureUrl string `json:"failure_url,omitempty"`
111+
PaymentIp string `json:"payment_ip,omitempty"`
112+
Sender Sender `json:"sender,omitempty"`
113+
Recipient *payments.PaymentRecipient `json:"recipient,omitempty"`
114+
Marketplace *common.MarketplaceData `json:"marketplace,omitempty"`
115+
AmountAllocations []common.AmountAllocations `json:"amount_allocations,omitempty"`
116+
Processing *payments.ProcessingSettings `json:"processing,omitempty"`
117+
Items []payments.Product `json:"items,omitempty"`
118+
Retry *payments.PaymentRetryRequest `json:"retry,omitempty"`
119+
Metadata map[string]interface{} `json:"metadata,omitempty"`
120+
Instruction *PaymentInstruction `json:"instruction,omitempty"`
116121
}
117122

118123
PayoutRequest struct {

payments/nas/sources/contexts/contexts.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ type (
1212
}
1313

1414
requestPaymentContextsPayPalSource struct {
15-
Type payments.SourceType `json:"type,omitempty"`
15+
Type payments.SourceType `json:"type,omitempty"`
16+
AccountHolder *common.AccountHolder `json:"account_holder,omitempty"`
1617
}
1718
)
1819

test/deserializer_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,44 @@ func TestControlsUnmarshallJson(t *testing.T) {
107107
})
108108
}
109109
}
110+
111+
func TestPaymentContextUnmarshallJson(t *testing.T) {
112+
paypalResponse, _ := ioutil.ReadFile("resources/payment_context_paypal_details_response.json")
113+
114+
cases := []struct {
115+
name string
116+
json []byte
117+
checker func(*bytes.Buffer, error)
118+
}{
119+
{
120+
name: "when deserializing payment_context_paypal_details_response type must be PayPal",
121+
json: paypalResponse,
122+
checker: func(serialized *bytes.Buffer, err error) {
123+
assert.Nil(t, err)
124+
assert.NotNil(t, serialized)
125+
126+
var deserialized map[string]interface{}
127+
unmErr := json.Unmarshal(serialized.Bytes(), &deserialized)
128+
129+
assert.Nil(t, unmErr)
130+
assert.NotNil(t, deserialized["payment_request"])
131+
paymentRequest := deserialized["payment_request"].(map[string]interface{})
132+
source := paymentRequest["source"].(map[string]interface{})
133+
134+
assert.Equal(t, "paypal", source["type"])
135+
assert.Contains(t, source, "type")
136+
assert.Contains(t, source, "account_holder")
137+
138+
accountHolder := source["account_holder"].(map[string]interface{})
139+
assert.Contains(t, accountHolder, "full_name")
140+
assert.Equal(t, "Andrey Young", accountHolder["full_name"])
141+
},
142+
},
143+
}
144+
145+
for _, tc := range cases {
146+
t.Run(tc.name, func(t *testing.T) {
147+
tc.checker(bytes.NewBuffer(tc.json), nil)
148+
})
149+
}
150+
}

test/payments_increment_authorization_test.go

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import (
77
"github.com/google/uuid"
88
"github.com/stretchr/testify/assert"
99

10+
"github.com/checkout/checkout-sdk-go/common"
1011
"github.com/checkout/checkout-sdk-go/payments"
1112
"github.com/checkout/checkout-sdk-go/payments/nas"
13+
"github.com/checkout/checkout-sdk-go/payments/nas/sources"
1214
)
1315

1416
func TestIncrementAuthorization(t *testing.T) {
15-
t.Skip("Skipping because increment authorization needs an authorized payment")
16-
paymentResponse := makeCardPayment(t, false, 10)
17+
paymentResponse := makeCardPaymentPartialAuthorization(t, false, 10)
18+
assert.NotNil(t, paymentResponse, "Expected paymentResponse not to be nil")
1719

1820
metadata := make(map[string]interface{})
1921
metadata["TestIncrementAuthorization"] = "metadata"
@@ -38,20 +40,26 @@ func TestIncrementAuthorization(t *testing.T) {
3840
checkerOne: func(response *nas.IncrementAuthorizationResponse, err error) {
3941
assert.Nil(t, err)
4042
assert.NotNil(t, response)
41-
assert.NotEmpty(t, response.Reference)
43+
assert.Equal(t, int64(5), response.Amount)
4244
assert.NotEmpty(t, response.ActionId)
45+
assert.NotEmpty(t, response.Currency)
46+
assert.False(t, response.Approved)
47+
assert.NotEmpty(t, response.ResponseCode)
48+
assert.NotEmpty(t, response.ResponseSummary)
49+
assert.NotEmpty(t, response.ExpiresOn)
50+
assert.NotEmpty(t, response.ProcessedOn)
51+
assert.NotEmpty(t, response.Balances)
4352
assert.NotEmpty(t, response.Links)
44-
assert.NotEmpty(t, response.Links["payment"])
4553
},
4654
checkerTwo: func(response *nas.GetPaymentResponse, err error) {
4755
assert.NotEmpty(t, response.Balances)
4856
assert.Equal(t, int64(10), response.Balances.TotalAuthorized)
49-
assert.Equal(t, int64(5), response.Balances.TotalCaptured)
57+
assert.Equal(t, int64(0), response.Balances.TotalCaptured)
5058
assert.Equal(t, int64(0), response.Balances.TotalRefunded)
5159
assert.Equal(t, int64(0), response.Balances.TotalVoided)
52-
assert.Equal(t, int64(0), response.Balances.AvailableToCapture)
53-
assert.Equal(t, int64(5), response.Balances.AvailableToRefund)
54-
assert.Equal(t, int64(0), response.Balances.AvailableToVoid)
60+
assert.Equal(t, int64(10), response.Balances.AvailableToCapture)
61+
assert.Equal(t, int64(0), response.Balances.AvailableToRefund)
62+
assert.Equal(t, int64(10), response.Balances.AvailableToVoid)
5563
},
5664
},
5765
}
@@ -69,8 +77,8 @@ func TestIncrementAuthorization(t *testing.T) {
6977
}
7078

7179
func TestIncrementAuthorizationIdempotently(t *testing.T) {
72-
t.Skip("Skipping because increment authorization needs an authorized payment")
73-
paymentResponse := makeCardPayment(t, false, 10)
80+
paymentResponse := makeCardPaymentPartialAuthorization(t, false, 10)
81+
assert.NotNil(t, paymentResponse, "Expected paymentResponse not to be nil")
7482

7583
metadata := make(map[string]interface{})
7684
metadata["TestIncrementAuthorization"] = "metadata"
@@ -115,7 +123,9 @@ func TestIncrementAuthorizationIdempotently(t *testing.T) {
115123
checker: func(response1 interface{}, err1 error, response2 interface{}, err2 error) {
116124
assert.Nil(t, err1)
117125
assert.NotNil(t, response1)
118-
assert.NotNil(t, err2)
126+
assert.Nil(t, err2)
127+
assert.NotNil(t, response2)
128+
assert.NotEqual(t, response1.(*nas.IncrementAuthorizationResponse).ActionId, response2.(*nas.IncrementAuthorizationResponse).ActionId)
119129
},
120130
},
121131
}
@@ -128,15 +138,15 @@ func TestIncrementAuthorizationIdempotently(t *testing.T) {
128138
return client.IncrementAuthorization(tc.paymentId, tc.request, &tc.idempotencyKeyRandom1)
129139
}
130140
predicateOne := func(data interface{}) bool {
131-
response := data.(*payments.CaptureResponse)
141+
response := data.(*nas.IncrementAuthorizationResponse)
132142
return response.Links != nil && len(response.Links) >= 0
133143
}
134144

135145
processTwo := func() (interface{}, error) {
136146
return client.IncrementAuthorization(tc.paymentId, tc.request, &tc.idempotencyKeyRandom2)
137147
}
138148
predicateTwo := func(data interface{}) bool {
139-
response := data.(*payments.CaptureResponse)
149+
response := data.(*nas.IncrementAuthorizationResponse)
140150
return response.Links != nil && len(response.Links) >= 0
141151
}
142152

@@ -146,3 +156,71 @@ func TestIncrementAuthorizationIdempotently(t *testing.T) {
146156
})
147157
}
148158
}
159+
160+
func makeCardPaymentPartialAuthorization(t *testing.T, shouldCapture bool, amount int64) *nas.PaymentResponse {
161+
currentYear := time.Now().Year() + 1
162+
163+
cardSource := sources.NewRequestCardSource()
164+
cardSource.Name = "Mr. Test"
165+
cardSource.Number = "4556447238607884"
166+
cardSource.ExpiryYear = currentYear
167+
cardSource.ExpiryMonth = 12
168+
cardSource.Cvv = "123"
169+
cardSource.BillingAddress = &common.Address{
170+
AddressLine1: "CheckoutSdk.com",
171+
AddressLine2: "90 Tottenham Court Road",
172+
City: "London",
173+
State: "London",
174+
Zip: "W1T 4TJ",
175+
Country: common.GB,
176+
}
177+
cardSource.Phone = &common.Phone{
178+
CountryCode: "44",
179+
Number: "1234567890",
180+
}
181+
182+
customerRequest := &common.CustomerRequest{
183+
184+
Name: "Test Customer",
185+
Phone: &common.Phone{
186+
CountryCode: "44",
187+
Number: "1234567890",
188+
},
189+
}
190+
191+
paymentIndividualSender := nas.NewRequestIndividualSender()
192+
paymentIndividualSender.FirstName = "Mr"
193+
paymentIndividualSender.LastName = "Test"
194+
paymentIndividualSender.Address = &common.Address{
195+
AddressLine1: "CheckoutSdk.com",
196+
AddressLine2: "90 Tottenham Court Road",
197+
City: "London",
198+
State: "London",
199+
Zip: "W1T 4TJ",
200+
Country: common.GB,
201+
}
202+
203+
paymentRequest := nas.PaymentRequest{
204+
Source: cardSource,
205+
Amount: amount,
206+
Currency: common.USD,
207+
Reference: uuid.New().String(),
208+
Description: "Test Payment",
209+
Capture: shouldCapture,
210+
Customer: customerRequest,
211+
Sender: paymentIndividualSender,
212+
AuthorizationType: nas.EstimatedAuthorizationType,
213+
PartialAuthorization: &nas.PartialAuthorization{
214+
Enabled: true,
215+
},
216+
BillingDescriptor: &payments.BillingDescriptor{
217+
Name: "CheckoutSdk.com",
218+
City: "London",
219+
},
220+
}
221+
222+
response, err := DefaultApi().Payments.RequestPayment(paymentRequest, nil)
223+
assert.Nil(t, err, "Expected no error in RequestPayment")
224+
assert.NotNil(t, response, "Expected response not to be nil")
225+
return response
226+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"partner_metadata": {
3+
"customer_id": "EWR4HCRWOEIW4",
4+
"order_id": "NF89G5J9E5G905E90"
5+
},
6+
"payment_request": {
7+
"amount": 2500,
8+
"authorization_type": "Final",
9+
"capture": true,
10+
"currency": "GBP",
11+
"failure_url": "https://url/payment-failed",
12+
"items": [
13+
{
14+
"discount_amount": 0,
15+
"name": "£25.00 Voucher",
16+
"quantity": 1,
17+
"tax_amount": 0,
18+
"total_amount": 2500,
19+
"unit_price": 2500
20+
}
21+
],
22+
"payment_type": "Regular",
23+
"processing": {
24+
"shipping_amount": 0,
25+
"user_action": "PAY_NOW"
26+
},
27+
"processing_channel_id": "pc_strugfrty47ellyymdfg6fzhc4i",
28+
"reference": "543454",
29+
"shipping": {
30+
"address": {
31+
"address_line1": "Main Address",
32+
"address_line2": "Flor 1",
33+
"city": "London",
34+
"country": "GB",
35+
"state": "State",
36+
"zip": "ZIP"
37+
},
38+
"first_name": "Andrey Young"
39+
},
40+
"source": {
41+
"account_holder": {
42+
"email": "[email protected]",
43+
"full_name": "Andrey Young"
44+
},
45+
"type": "paypal"
46+
},
47+
"success_url": "https://url/payment-successful"
48+
},
49+
"status": "Created"
50+
}

0 commit comments

Comments
 (0)