Skip to content

Commit 8c7ca9c

Browse files
authored
Merge pull request #117 from alberto1el/master
CIM Add ability to create Customer Profile with OpaqueData from Accept.js
2 parents a9738c3 + 5988948 commit 8c7ca9c

File tree

5 files changed

+145
-14
lines changed

5 files changed

+145
-14
lines changed

README.md

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The following gateways are provided by this package:
2626
* AuthorizeNet_SIM
2727
* AuthorizeNet_DPM
2828

29-
In addition, `Accept.JS` is supported by the AIM driver. More details are provided below.
29+
In addition, `Accept.JS` is supported by the AIM driver and CIM (create card). More details are provided below.
3030

3131
For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay)
3232
repository.
@@ -45,15 +45,15 @@ The card is tokenized into two values returned in `opaqueData` object from Accep
4545

4646
These two values must be POSTed back to the merchant application, usually as a part of the payment form.
4747
Make sure the raw credit card details are NOT posted back to your site.
48-
How this is handled is beyond this short note, but examples are always welcome in the documentation.
48+
How this is handled is beyond this short note, but examples are always welcomed in the documentation.
4949

50-
On the server, the tokenized detailt are passed into the `payment` or `authorize` request object.
50+
On the server, the tokenized details are passed into the `payment` or `authorize` request object.
5151
You will still need to pass in the `CreditCard` object, as that contains details of the payee and
5252
recipient, but just leave the credit card details of that object blank. For example:
5353

5454
```php
5555
// $gateway is an instantiation of the AIM driver.
56-
// $dataDescriptor and $dataValue come from the paymentr form at the front end.
56+
// $dataDescriptor and $dataValue come from the payment form at the front end.
5757

5858
$request = $gateway->purchase(
5959
[
@@ -66,6 +66,56 @@ $request = $gateway->purchase(
6666
);
6767
```
6868

69+
CIM Create Card feature usage:
70+
Accept.js must be implemented on your frontend payment form, once Accept.js 'tokenizes' the customer's
71+
card, just send the two opaque fields and remove the Card's (Number, Expiration and CVV) from your post request.
72+
73+
Accept.js goal is to remove the need of Card information from ever going into your server so be sure to remove that data
74+
before posting to your server.
75+
76+
The create card feature on CIM will automatically create a Customer Profile and a Payment Profile with the
77+
'tokenized' card for each customer you request it for on your authorize.net account, you can use these Payment Profiles
78+
later to request payments from your customers.
79+
80+
In order to create a Customer & Payment Profile pass the opaque fields and the card array with the billing information
81+
to the createCard method on the CIM driver:
82+
83+
```php
84+
// $gateway is an instantiation of the CIM driver. //Omnipay::create( 'AuthorizeNet_CIM' )
85+
// $dataDescriptor and $dataValue come from the payment form at the front end.
86+
87+
$request = $gateway->createCard(
88+
[
89+
'opaqueDataDescriptor' => $dataDescriptor,
90+
'opaqueDataValue' => $dataValue,
91+
'name' => $name,
92+
'email' => $email, //Authorize.net will use the email to identify the CustomerProfile
93+
'customerType' => 'individual',
94+
'customerId' => $user_customer_id,//a customer ID generated by your system or send null
95+
'description' => 'MEMBER',//whichever description you wish to send
96+
'forceCardUpdate' => true
97+
'card' => [
98+
'billingFirstName' => $name,
99+
'billingLastName' => $last_name,
100+
'billingAddress1' => $address,
101+
'billingCity' => $city,
102+
'billingState' => $state,
103+
'billingPostcode' => $zipcode,
104+
'billingPhone' => '',
105+
//... may include shipping info but do not include card (number, cvv or expiration)
106+
],
107+
]
108+
);
109+
$response = $request->send();
110+
$data = $response->getData();
111+
112+
$data['paymentProfile']['customerProfileId'];
113+
$data['paymentProfile']['customerPaymentProfileId'];
114+
//Now you can use these 2 fields to reference this customer and this payment profile for later use with
115+
//the rest of the CIM driver features as usual.
116+
```
117+
118+
69119
## Support
70120

71121
If you are having general issues with Omnipay, we suggest posting on

src/Message/CIMCreateCardRequest.php

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,33 @@ class CIMCreateCardRequest extends CIMAbstractRequest
1313

1414
public function getData()
1515
{
16-
$this->validate('card');
17-
18-
/** @var CreditCard $card */
19-
$card = $this->getCard();
20-
$card->validate();
2116

17+
$this->validate('card');
18+
$this->cardValidate();
2219
$data = $this->getBaseData();
2320
$this->addProfileData($data);
2421
$this->addTransactionSettings($data);
2522

2623
return $data;
2724
}
2825

26+
/**
27+
* Validate card or skip if opaque data is available
28+
*
29+
* @param \SimpleXMLElement $data
30+
*/
31+
protected function cardValidate()
32+
{
33+
34+
if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) {
35+
return;
36+
}
37+
38+
/** @var CreditCard $card */
39+
$card = $this->getCard();
40+
$card->validate();
41+
}
42+
2943
/**
3044
* Add customer profile data to the specified xml element
3145
*
@@ -97,12 +111,18 @@ protected function addBillingData(\SimpleXMLElement $data)
97111
}
98112

99113
$req = $data->addChild('payment');
100-
$req->creditCard->cardNumber = $card->getNumber();
101-
$req->creditCard->expirationDate = $card->getExpiryDate('Y-m');
102-
if ($card->getCvv()) {
103-
$req->creditCard->cardCode = $card->getCvv();
114+
if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) {
115+
//Use opaqueData if available instead of card data
116+
$req->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor();
117+
$req->opaqueData->dataValue = $this->getOpaqueDataValue();
104118
} else {
105-
$this->setValidationMode(self::VALIDATION_MODE_NONE);
119+
$req->creditCard->cardNumber = $card->getNumber();
120+
$req->creditCard->expirationDate = $card->getExpiryDate('Y-m');
121+
if ($card->getCvv()) {
122+
$req->creditCard->cardCode = $card->getCvv();
123+
} else {
124+
$this->setValidationMode(self::VALIDATION_MODE_NONE);
125+
}
106126
}
107127
}
108128
}

tests/CIMGatewayTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ public function setUp()
3131
'forceCardUpdate' => true
3232
);
3333

34+
$validCard = $this->getValidCard();
35+
unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']);
36+
//remove the actual card data since we are setting opaque values
37+
$this->createCardFromOpaqueDataOptions = array(
38+
'email' => "[email protected]",
39+
'card' => $validCard,
40+
'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
41+
'opaqueDataValue' => 'jb2RlIjoiNTB',
42+
'testMode' => true,
43+
'forceCardUpdate' => true
44+
);
45+
3446
$this->authorizeOptions = array(
3547
'cardReference' => '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}',
3648
'amount' => 10.00,
@@ -89,6 +101,20 @@ public function testCreateCardSuccess()
89101
$this->assertSame('Successful.', $response->getMessage());
90102
}
91103

104+
public function testCreateCardFromOpaqueDataSuccess()
105+
{
106+
$this->setMockHttpResponse(array('CIMCreateCardSuccess.txt','CIMGetPaymentProfileSuccess.txt'));
107+
108+
$response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send();
109+
110+
$this->assertTrue($response->isSuccessful());
111+
$this->assertSame(
112+
'{"customerProfileId":"28972084","customerPaymentProfileId":"26485433"}',
113+
$response->getCardReference()
114+
);
115+
$this->assertSame('Successful.', $response->getMessage());
116+
}
117+
92118
public function testShouldCreateCardIfDuplicateCustomerProfileExists()
93119
{
94120
$this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt',

tests/Message/CIMCreateCardRequestTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,25 @@ public function testGetDataShouldSetValidationModeToNoneIfNoCvvProvided()
5959
$this->assertFalse(isset($data->profile->paymentProfiles->payment->creditCard->cardCode));
6060
$this->assertEquals(CIMCreatePaymentProfileRequest::VALIDATION_MODE_NONE, $this->request->getValidationMode());
6161
}
62+
63+
public function testGetDataOpaqueData()
64+
{
65+
66+
$validCard = $this->getValidCard();
67+
unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']);
68+
//remove the actual card data since we are setting opaque values
69+
$this->params = array(
70+
'email' => "[email protected]",
71+
'card' => $validCard,
72+
'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
73+
'opaqueDataValue' => 'jb2RlIjoiNTB',
74+
'developerMode' => true
75+
);
76+
$this->request->initialize($this->params);
77+
78+
$data = $this->request->getData();
79+
80+
$this->assertEquals('COMMON.ACCEPT.INAPP.PAYMENT', $data->profile->paymentProfiles->payment->opaqueData->dataDescriptor);
81+
$this->assertEquals('jb2RlIjoiNTB', $data->profile->paymentProfiles->payment->opaqueData->dataValue);
82+
}
6283
}

tests/Message/CIMCreateCardResponseTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,18 @@ public function testCreateCardFailure()
4343

4444
$this->assertNull($response->getCardReference());
4545
}
46+
47+
public function testCreateCardSuccessFromOpaqueData()
48+
{
49+
$httpResponse = $this->getMockHttpResponse('CIMCreateCardSuccess.txt');
50+
$response = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody());
51+
52+
$this->assertTrue($response->isSuccessful());
53+
$this->assertEquals('I00001', $response->getReasonCode());
54+
$this->assertEquals("1", $response->getResultCode());
55+
$this->assertEquals("Successful.", $response->getMessage());
56+
57+
$this->assertEquals('28972084', $response->getCustomerProfileId());
58+
$this->assertEquals('26317840', $response->getCustomerPaymentProfileId());
59+
}
4660
}

0 commit comments

Comments
 (0)