Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Allow MPC support for cybersource (#226)
Browse files Browse the repository at this point in the history
* Allow MPC support for cybersource

* Cleanup

* lint fix
  • Loading branch information
UnitRoot22 authored Apr 28, 2022
1 parent 168b1db commit 017b0c3
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 60 deletions.
122 changes: 84 additions & 38 deletions gateways/cybersource/request_builder_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// +build unit

package cybersource

import (
Expand Down Expand Up @@ -43,9 +41,9 @@ func TestBuildAuthRequest(t *testing.T) {
CommerceIndicator: "internet",
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: "",
InitiatorType: "",
CredentialStoredOnFile: false,
StoredCredentialUsed: false,
StoredCredentialUsed: false,
},
},
},
Expand Down Expand Up @@ -98,25 +96,25 @@ func TestBuildAuthRequest(t *testing.T) {
CommerceIndicator: "internet",
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: "",
InitiatorType: "",
CredentialStoredOnFile: false,
StoredCredentialUsed: false,
StoredCredentialUsed: false,
},
},
PaymentSolution: "001", // Apple pay
PaymentSolution: "001", // Apple pay
},
PaymentInformation: &PaymentInformation{
TokenizedCard: &TokenizedCard{
Number: visaApplepayBase.CreditCard.Number,
Number: visaApplepayBase.CreditCard.Number,
ExpirationYear: strconv.Itoa(visaApplepayBase.CreditCard.ExpirationYear),
ExpirationMonth: fmt.Sprintf("%02d", visaApplepayBase.CreditCard.ExpirationMonth),
TransactionType: "1",
Cryptogram: visaApplepayBase.Cryptogram,
Type: "001",
Cryptogram: visaApplepayBase.Cryptogram,
Type: "001",
},
},
ConsumerAuthenticationInformation: &ConsumerAuthenticationInformation{
Xid: visaApplepayBase.Cryptogram,
Xid: visaApplepayBase.Cryptogram,
Cavv: visaApplepayBase.Cryptogram,
},
OrderInformation: &OrderInformation{
Expand Down Expand Up @@ -160,25 +158,25 @@ func TestBuildAuthRequest(t *testing.T) {
CommerceIndicator: "spa",
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: "",
InitiatorType: "",
CredentialStoredOnFile: false,
StoredCredentialUsed: false,
StoredCredentialUsed: false,
},
},
PaymentSolution: "001", // Apple pay
PaymentSolution: "001", // Apple pay
},
PaymentInformation: &PaymentInformation{
TokenizedCard: &TokenizedCard{
Number: mastercardApplepayBase.CreditCard.Number,
Number: mastercardApplepayBase.CreditCard.Number,
ExpirationYear: strconv.Itoa(mastercardApplepayBase.CreditCard.ExpirationYear),
ExpirationMonth: fmt.Sprintf("%02d", mastercardApplepayBase.CreditCard.ExpirationMonth),
TransactionType: "1",
Cryptogram: mastercardApplepayBase.Cryptogram,
Type: "002",
Cryptogram: mastercardApplepayBase.Cryptogram,
Type: "002",
},
},
ConsumerAuthenticationInformation: &ConsumerAuthenticationInformation{
UcafAuthenticationData: mastercardApplepayBase.Cryptogram,
UcafAuthenticationData: mastercardApplepayBase.Cryptogram,
UcafCollectionIndicator: "2",
},
OrderInformation: &OrderInformation{
Expand Down Expand Up @@ -222,21 +220,21 @@ func TestBuildAuthRequest(t *testing.T) {
CommerceIndicator: "dipb",
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: "",
InitiatorType: "",
CredentialStoredOnFile: false,
StoredCredentialUsed: false,
StoredCredentialUsed: false,
},
},
PaymentSolution: "001", // Apple pay
PaymentSolution: "001", // Apple pay
},
PaymentInformation: &PaymentInformation{
TokenizedCard: &TokenizedCard{
Number: discoverApplepayBase.CreditCard.Number,
Number: discoverApplepayBase.CreditCard.Number,
ExpirationYear: strconv.Itoa(discoverApplepayBase.CreditCard.ExpirationYear),
ExpirationMonth: fmt.Sprintf("%02d", discoverApplepayBase.CreditCard.ExpirationMonth),
TransactionType: "1",
Cryptogram: discoverApplepayBase.Cryptogram,
Type: "004",
Cryptogram: discoverApplepayBase.Cryptogram,
Type: "004",
},
},
ConsumerAuthenticationInformation: &ConsumerAuthenticationInformation{
Expand Down Expand Up @@ -283,21 +281,21 @@ func TestBuildAuthRequest(t *testing.T) {
CommerceIndicator: "aesk",
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: "",
InitiatorType: "",
CredentialStoredOnFile: false,
StoredCredentialUsed: false,
StoredCredentialUsed: false,
},
},
PaymentSolution: "001", // Apple pay
PaymentSolution: "001", // Apple pay
},
PaymentInformation: &PaymentInformation{
TokenizedCard: &TokenizedCard{
Number: amexApplepayBase.CreditCard.Number,
Number: amexApplepayBase.CreditCard.Number,
ExpirationYear: strconv.Itoa(amexApplepayBase.CreditCard.ExpirationYear),
ExpirationMonth: fmt.Sprintf("%02d", amexApplepayBase.CreditCard.ExpirationMonth),
TransactionType: "1",
Cryptogram: amexApplepayBase.Cryptogram,
Type: "003",
Cryptogram: amexApplepayBase.Cryptogram,
Type: "003",
},
},
ConsumerAuthenticationInformation: &ConsumerAuthenticationInformation{
Expand Down Expand Up @@ -344,26 +342,26 @@ func TestBuildAuthRequest(t *testing.T) {
CommerceIndicator: "aesk",
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: "",
InitiatorType: "",
CredentialStoredOnFile: false,
StoredCredentialUsed: false,
StoredCredentialUsed: false,
},
},
PaymentSolution: "001", // Apple pay
PaymentSolution: "001", // Apple pay
},
PaymentInformation: &PaymentInformation{
TokenizedCard: &TokenizedCard{
Number: amexLongCryptoApplepayBase.CreditCard.Number,
Number: amexLongCryptoApplepayBase.CreditCard.Number,
ExpirationYear: strconv.Itoa(amexLongCryptoApplepayBase.CreditCard.ExpirationYear),
ExpirationMonth: fmt.Sprintf("%02d", amexLongCryptoApplepayBase.CreditCard.ExpirationMonth),
TransactionType: "1",
Cryptogram: amexLongCryptoApplepayBase.Cryptogram,
Type: "003",
Cryptogram: amexLongCryptoApplepayBase.Cryptogram,
Type: "003",
},
},
ConsumerAuthenticationInformation: &ConsumerAuthenticationInformation{
Cavv: amexLongCryptoApplepayBase.Cryptogram[:20],
Xid: amexLongCryptoApplepayBase.Cryptogram[20:],
Xid: amexLongCryptoApplepayBase.Cryptogram[20:],
},
OrderInformation: &OrderInformation{
AmountDetails: AmountDetails{
Expand Down Expand Up @@ -415,7 +413,7 @@ func TestBuildCaptureRequest(t *testing.T) {
{
"Basic Capture Request",
base,
&Request {
&Request{
OrderInformation: &OrderInformation{
AmountDetails: AmountDetails{
Amount: "1.00",
Expand Down Expand Up @@ -535,3 +533,51 @@ func getBaseAuthorizationRequest(network sleet.CreditCardNetwork, cryptogram str

return base
}

func TestBuildCaptureRequestWithOptions(t *testing.T) {
base := sleet_testing.BaseCaptureRequestWithOptions()
base.MerchantOrderReference = common.SPtr("cart_display_id")

cases := []struct {
label string
in *sleet.CaptureRequest
want *Request
}{
{
"Basic Capture Request with options",
base,
&Request{
OrderInformation: &OrderInformation{
AmountDetails: AmountDetails{
Amount: "1.00",
Currency: "USD",
},
},
ClientReferenceInformation: &ClientReferenceInformation{
Code: *base.MerchantOrderReference,
},
MerchantDefinedInformation: []MerchantDefinedInformation{
{
Key: "1",
Value: *base.ClientTransactionReference,
},
},
ProcessingInformation: &ProcessingInformation{
CaptureOptions: &CaptureOptions{
CaptureSequenceNumber: "11",
TotalCaptureCount: "99",
},
},
},
},
}

for _, c := range cases {
t.Run(c.label, func(t *testing.T) {
got, _ := buildCaptureRequest(c.in)
if diff := deep.Equal(got, c.want); diff != nil {
t.Error(diff)
}
})
}
}
46 changes: 32 additions & 14 deletions gateways/cybersource/request_builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ const (
const (
AmexCryptogramMaxLength = 40
AmexCryptogramSplitLength = 20
TransactionTypeInApp = "1"
PaymentSolutionApplepay = "001"
TransactionTypeInApp = "1"
PaymentSolutionApplepay = "001"
)

// Options
const (
captureSequenceNumber = "captureSequenceNumber"
totalCaptureCount = "totalCaptureCount"
)

// add mappings
Expand Down Expand Up @@ -69,9 +75,9 @@ func buildAuthRequest(authRequest *sleet.AuthorizationRequest) (*Request, error)
CommerceIndicator: string(CommerceIndicatorInternet),
AuthorizationOptions: &AuthorizationOptions{
Initiator: &Initiator{
InitiatorType: initiatorType,
InitiatorType: initiatorType,
CredentialStoredOnFile: credentialStoredOnFile,
StoredCredentialUsed: storedCredentialUsed,
StoredCredentialUsed: storedCredentialUsed,
},
},
},
Expand Down Expand Up @@ -114,7 +120,7 @@ func buildAuthRequest(authRequest *sleet.AuthorizationRequest) (*Request, error)
// If level 3 data is present, and ClientReferenceInformation in that data exists, it will override this.
if authRequest.ClientTransactionReference != nil {
request.MerchantDefinedInformation = append(request.MerchantDefinedInformation, MerchantDefinedInformation{
Key: "1",
Key: "1",
Value: *authRequest.ClientTransactionReference,
})
}
Expand Down Expand Up @@ -169,10 +175,22 @@ func buildCaptureRequest(captureRequest *sleet.CaptureRequest) (*Request, error)
}
if captureRequest.ClientTransactionReference != nil {
request.MerchantDefinedInformation = append(request.MerchantDefinedInformation, MerchantDefinedInformation{
Key: "1",
Key: "1",
Value: *captureRequest.ClientTransactionReference,
})
}
captureSeqNum, ok := captureRequest.Options[captureSequenceNumber]
if ok {
totalCapCount, ok := captureRequest.Options[totalCaptureCount]
if ok {
request.ProcessingInformation = &ProcessingInformation{
CaptureOptions: &CaptureOptions{
CaptureSequenceNumber: captureSeqNum.(string),
TotalCaptureCount: totalCapCount.(string),
},
}
}
}
return request, nil
}

Expand All @@ -186,7 +204,7 @@ func buildVoidRequest(voidRequest *sleet.VoidRequest) (*Request, error) {
}
if voidRequest.ClientTransactionReference != nil {
request.MerchantDefinedInformation = append(request.MerchantDefinedInformation, MerchantDefinedInformation{
Key: "1",
Key: "1",
Value: *voidRequest.ClientTransactionReference,
})
}
Expand All @@ -210,7 +228,7 @@ func buildRefundRequest(refundRequest *sleet.RefundRequest) (*Request, error) {
}
if refundRequest.ClientTransactionReference != nil {
request.MerchantDefinedInformation = append(request.MerchantDefinedInformation, MerchantDefinedInformation{
Key: "1",
Key: "1",
Value: *refundRequest.ClientTransactionReference,
})
}
Expand All @@ -220,11 +238,11 @@ func buildRefundRequest(refundRequest *sleet.RefundRequest) (*Request, error) {
func buildApplepayRequest(authRequest *sleet.AuthorizationRequest, request *Request) error {
request.PaymentInformation = &PaymentInformation{
TokenizedCard: &TokenizedCard{
Number: authRequest.CreditCard.Number,
ExpirationYear: strconv.Itoa(authRequest.CreditCard.ExpirationYear),
Number: authRequest.CreditCard.Number,
ExpirationYear: strconv.Itoa(authRequest.CreditCard.ExpirationYear),
ExpirationMonth: fmt.Sprintf("%02d", authRequest.CreditCard.ExpirationMonth),
TransactionType: TransactionTypeInApp,
Cryptogram: authRequest.Cryptogram,
Cryptogram: authRequest.Cryptogram,
},
}

Expand All @@ -234,14 +252,14 @@ func buildApplepayRequest(authRequest *sleet.AuthorizationRequest, request *Requ
case sleet.CreditCardNetworkVisa:
request.PaymentInformation.TokenizedCard.Type = string(CardTypeVisa)
request.ConsumerAuthenticationInformation = &ConsumerAuthenticationInformation{
Xid: authRequest.Cryptogram,
Xid: authRequest.Cryptogram,
Cavv: authRequest.Cryptogram,
}
case sleet.CreditCardNetworkMastercard:
request.PaymentInformation.TokenizedCard.Type = string(CardTypeMastercard)
request.ProcessingInformation.CommerceIndicator = string(CommerceIndicatorMastercard)
request.ConsumerAuthenticationInformation = &ConsumerAuthenticationInformation{
UcafAuthenticationData: authRequest.Cryptogram,
UcafAuthenticationData: authRequest.Cryptogram,
UcafCollectionIndicator: "2",
}
case sleet.CreditCardNetworkAmex:
Expand Down Expand Up @@ -274,7 +292,7 @@ func getAmexConsumerAuthInfo(cryptogram string) (*ConsumerAuthenticationInformat
// the xid field.
return &ConsumerAuthenticationInformation{
Cavv: cryptogram[:AmexCryptogramSplitLength],
Xid: cryptogram[AmexCryptogramSplitLength:],
Xid: cryptogram[AmexCryptogramSplitLength:],
}, nil
}

Expand Down
6 changes: 6 additions & 0 deletions gateways/cybersource/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ type ProcessorInformation struct {
// ProcessingInformation specifies various fields for authorize for options (auto-capture, Level3 Data, etc)
type ProcessingInformation struct {
Capture bool `json:"capture,omitempty"`
CaptureOptions *CaptureOptions `json:"captureOptions,omitempty"`
CommerceIndicator string `json:"commerceIndicator"` // typically internet
PaymentSolution string `json:"paymentSolution"`
PurchaseLevel string `json:"purchaseLevel,omitempty"` // Specifies if level 3 data is being sent
Expand Down Expand Up @@ -217,3 +218,8 @@ type ConsumerAuthenticationInformation struct {
Xid string `json:"xid,omitempty"`
Cavv string `json:"cavv,omitempty"`
}

type CaptureOptions struct {
CaptureSequenceNumber string `json:"captureSequenceNumber,omitempty"`
TotalCaptureCount string `json:"totalCaptureCount,omitempty"`
}
18 changes: 18 additions & 0 deletions testing/auth_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,21 @@ func Base3DS() *sleet.ThreeDS {
XID: "xid",
}
}

func BaseCaptureRequestWithOptions() *sleet.CaptureRequest {
clientRef := "222222"

amount := sleet.Amount{
Amount: 100,
Currency: "USD",
}
return &sleet.CaptureRequest{
Amount: &amount,
TransactionReference: "111111",
ClientTransactionReference: &clientRef,
Options: map[string]interface{}{
"captureSequenceNumber": "11",
"totalCaptureCount": "99",
},
}
}
Loading

0 comments on commit 017b0c3

Please sign in to comment.