Skip to content

Commit

Permalink
Merge pull request #117 from alberto1el/master
Browse files Browse the repository at this point in the history
CIM Add ability to create Customer Profile with OpaqueData from Accept.js
  • Loading branch information
judgej authored Dec 31, 2018
2 parents a9738c3 + 5988948 commit 8c7ca9c
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 14 deletions.
58 changes: 54 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The following gateways are provided by this package:
* AuthorizeNet_SIM
* AuthorizeNet_DPM

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

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

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

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

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

$request = $gateway->purchase(
[
Expand All @@ -66,6 +66,56 @@ $request = $gateway->purchase(
);
```

CIM Create Card feature usage:
Accept.js must be implemented on your frontend payment form, once Accept.js 'tokenizes' the customer's
card, just send the two opaque fields and remove the Card's (Number, Expiration and CVV) from your post request.

Accept.js goal is to remove the need of Card information from ever going into your server so be sure to remove that data
before posting to your server.

The create card feature on CIM will automatically create a Customer Profile and a Payment Profile with the
'tokenized' card for each customer you request it for on your authorize.net account, you can use these Payment Profiles
later to request payments from your customers.

In order to create a Customer & Payment Profile pass the opaque fields and the card array with the billing information
to the createCard method on the CIM driver:

```php
// $gateway is an instantiation of the CIM driver. //Omnipay::create( 'AuthorizeNet_CIM' )
// $dataDescriptor and $dataValue come from the payment form at the front end.

$request = $gateway->createCard(
[
'opaqueDataDescriptor' => $dataDescriptor,
'opaqueDataValue' => $dataValue,
'name' => $name,
'email' => $email, //Authorize.net will use the email to identify the CustomerProfile
'customerType' => 'individual',
'customerId' => $user_customer_id,//a customer ID generated by your system or send null
'description' => 'MEMBER',//whichever description you wish to send
'forceCardUpdate' => true
'card' => [
'billingFirstName' => $name,
'billingLastName' => $last_name,
'billingAddress1' => $address,
'billingCity' => $city,
'billingState' => $state,
'billingPostcode' => $zipcode,
'billingPhone' => '',
//... may include shipping info but do not include card (number, cvv or expiration)
],
]
);
$response = $request->send();
$data = $response->getData();

$data['paymentProfile']['customerProfileId'];
$data['paymentProfile']['customerPaymentProfileId'];
//Now you can use these 2 fields to reference this customer and this payment profile for later use with
//the rest of the CIM driver features as usual.
```


## Support

If you are having general issues with Omnipay, we suggest posting on
Expand Down
40 changes: 30 additions & 10 deletions src/Message/CIMCreateCardRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,33 @@ class CIMCreateCardRequest extends CIMAbstractRequest

public function getData()
{
$this->validate('card');

/** @var CreditCard $card */
$card = $this->getCard();
$card->validate();

$this->validate('card');
$this->cardValidate();
$data = $this->getBaseData();
$this->addProfileData($data);
$this->addTransactionSettings($data);

return $data;
}

/**
* Validate card or skip if opaque data is available
*
* @param \SimpleXMLElement $data
*/
protected function cardValidate()
{

if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) {
return;
}

/** @var CreditCard $card */
$card = $this->getCard();
$card->validate();
}

/**
* Add customer profile data to the specified xml element
*
Expand Down Expand Up @@ -97,12 +111,18 @@ protected function addBillingData(\SimpleXMLElement $data)
}

$req = $data->addChild('payment');
$req->creditCard->cardNumber = $card->getNumber();
$req->creditCard->expirationDate = $card->getExpiryDate('Y-m');
if ($card->getCvv()) {
$req->creditCard->cardCode = $card->getCvv();
if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) {
//Use opaqueData if available instead of card data
$req->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor();
$req->opaqueData->dataValue = $this->getOpaqueDataValue();
} else {
$this->setValidationMode(self::VALIDATION_MODE_NONE);
$req->creditCard->cardNumber = $card->getNumber();
$req->creditCard->expirationDate = $card->getExpiryDate('Y-m');
if ($card->getCvv()) {
$req->creditCard->cardCode = $card->getCvv();
} else {
$this->setValidationMode(self::VALIDATION_MODE_NONE);
}
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions tests/CIMGatewayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ public function setUp()
'forceCardUpdate' => true
);

$validCard = $this->getValidCard();
unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']);
//remove the actual card data since we are setting opaque values
$this->createCardFromOpaqueDataOptions = array(
'email' => "[email protected]",
'card' => $validCard,
'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
'opaqueDataValue' => 'jb2RlIjoiNTB',
'testMode' => true,
'forceCardUpdate' => true
);

$this->authorizeOptions = array(
'cardReference' => '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}',
'amount' => 10.00,
Expand Down Expand Up @@ -89,6 +101,20 @@ public function testCreateCardSuccess()
$this->assertSame('Successful.', $response->getMessage());
}

public function testCreateCardFromOpaqueDataSuccess()
{
$this->setMockHttpResponse(array('CIMCreateCardSuccess.txt','CIMGetPaymentProfileSuccess.txt'));

$response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send();

$this->assertTrue($response->isSuccessful());
$this->assertSame(
'{"customerProfileId":"28972084","customerPaymentProfileId":"26485433"}',
$response->getCardReference()
);
$this->assertSame('Successful.', $response->getMessage());
}

public function testShouldCreateCardIfDuplicateCustomerProfileExists()
{
$this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt',
Expand Down
21 changes: 21 additions & 0 deletions tests/Message/CIMCreateCardRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,25 @@ public function testGetDataShouldSetValidationModeToNoneIfNoCvvProvided()
$this->assertFalse(isset($data->profile->paymentProfiles->payment->creditCard->cardCode));
$this->assertEquals(CIMCreatePaymentProfileRequest::VALIDATION_MODE_NONE, $this->request->getValidationMode());
}

public function testGetDataOpaqueData()
{

$validCard = $this->getValidCard();
unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']);
//remove the actual card data since we are setting opaque values
$this->params = array(
'email' => "[email protected]",
'card' => $validCard,
'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT',
'opaqueDataValue' => 'jb2RlIjoiNTB',
'developerMode' => true
);
$this->request->initialize($this->params);

$data = $this->request->getData();

$this->assertEquals('COMMON.ACCEPT.INAPP.PAYMENT', $data->profile->paymentProfiles->payment->opaqueData->dataDescriptor);
$this->assertEquals('jb2RlIjoiNTB', $data->profile->paymentProfiles->payment->opaqueData->dataValue);
}
}
14 changes: 14 additions & 0 deletions tests/Message/CIMCreateCardResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,18 @@ public function testCreateCardFailure()

$this->assertNull($response->getCardReference());
}

public function testCreateCardSuccessFromOpaqueData()
{
$httpResponse = $this->getMockHttpResponse('CIMCreateCardSuccess.txt');
$response = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody());

$this->assertTrue($response->isSuccessful());
$this->assertEquals('I00001', $response->getReasonCode());
$this->assertEquals("1", $response->getResultCode());
$this->assertEquals("Successful.", $response->getMessage());

$this->assertEquals('28972084', $response->getCustomerProfileId());
$this->assertEquals('26317840', $response->getCustomerPaymentProfileId());
}
}

0 comments on commit 8c7ca9c

Please sign in to comment.