Skip to content

Commit

Permalink
Issue #2 Add notification handler.
Browse files Browse the repository at this point in the history
  • Loading branch information
judgej committed May 30, 2018
1 parent cea6b80 commit 7be1f84
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 6 deletions.
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Table of Contents
* [API Fetch Transaction](#api-fetch-transaction)
* [Hosted Payment Page](#hosted-payment-page)
* [Hosted Payment Page Authorize/Purchase](#hosted-payment-page-authorizepurchase)
* [Webhook Notifications](#webhook-notifications)

# Omnipay-AuthorizeNetApi

Expand Down Expand Up @@ -387,3 +388,79 @@ or use the `set*()` form to do the same thing:

$request->setPaymentOptionsShowBankAccount(false);

# Webhook Notifications

The Authorize.Net gateway provides a rich set of webhooks to notify the
merchant site (and/or other backend systems) about events related to
customers or payments.
The [current documentation can be found here](https://developer.authorize.net/api/reference/features/webhooks.html).

For some API methods, such as the Hosted Payment Page, the webhooks
are necessary for operation. For other API methods they provide additional
information.

The webhooks can be configured in the Authorize.Net account settings page.
They can also be fully managed through a REST API, so that a merchant
site can register for all the webhooks that it needs.
*Note that the webhook management RESTful API has not yet been implemented here.*

Your notification handler is set up like this at your webhook endpoint:

```php
$gateway = Omnipay::create('AuthorizeNetApi_Api');

$gateway->setAuthName($authName);
$gateway->setTransactionKey($authKey);
$gateway->setTestMode(true); // for false

$notification = $gateway->acceptNotification();
```

This will read and parse the webhook `POST` data.
The raw nested array data can be found at:

$notification->getData();

The parsed `Notification` value object can be found at:

$notification->getParsedData();

Some details that describe the nature of the notification are:

```php
// The main target: payment or customer
$notification->getEventTarget();

// The event subtarget. e.g. capture, fraud, void, subscription
$notification->getEventSubtarget();

// The event action. e.g. created, updated, deleted, held, approved, declined
$notification->getEventMethod();
```

See here for a full list of the target, subtarget and actions:
https://github.com/academe/authorizenet-objects/blob/master/src/ServerRequest/Notification.php#L24

For those notifications that contain the `transactionReference`, this can be
obtained:

$notification->getTransactionReference();

For any notifications that do not involve a transaction, this will be `null`.
Note that the webhook does not include the merchant `transactionId`,
so there is nothing to tie the payment webhook back to a Hosted Page request.
In this case, you can supply the `transactionId` as a query parameter
on the `notifyUrl` when creating the Hosted Payment Page data.
However, do be aware this ID will be visible to end users monitoring
browser traffic, and the ID (being in the URL) will not be included
in the notification signing, so could be faked. It is unlikely, but just
be aware that it is a potential attack vector, so maybe self-sign the URL
too.

For consistency with other Omipay Driers, this driver *may* make an
opinionated decision on how the `transactionId` is passed into the
notification handler, but only after researchign how other people are
handling it.
There is a front-end way to do it through an iframe, but it seems
vulnerable to user manipulation to me.

110 changes: 104 additions & 6 deletions src/Message/AcceptNotification.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Omnipay\AuthorizeNetApi\Message;

/**
*
* TODO: validate the server request signature.
*/

use Omnipay\Common\Message\NotificationInterface;
Expand All @@ -13,6 +13,7 @@

use Omnipay\AuthorizeNetApi\Traits\HasGatewayParams;
use Academe\AuthorizeNet\ServerRequest\Notification;
use Academe\AuthorizeNet\Response\Model\TransactionResponse;

class AcceptNotification extends AbstractRequest implements NotificationInterface //, RequestInterface
{
Expand All @@ -25,8 +26,6 @@ class AcceptNotification extends AbstractRequest implements NotificationInterfac
*/
protected $parsedData;

protected $notification;

public function __construct(ClientInterface $httpClient, HttpRequest $httpRequest)
{
// The request is a \Symfony/Component/HttpFoundation/Request object
Expand Down Expand Up @@ -77,7 +76,9 @@ public function getData()
*/
public function getTransactionReference()
{
// TODO.
if ($this->getEventTarget() === $this->getParsedData()::EVENT_TARGET_PAYMENT) {
return $this->getPayload()->getTransId();
}
}

/**
Expand All @@ -88,7 +89,15 @@ public function getTransactionReference()
*/
public function getTransactionStatus()
{
// TODO.
$responseCode = $this->getResponseCode();

if ($responseCode === TransactionResponse::RESPONSE_CODE_APPROVED) {
return static::STATUS_COMPLETED;
} elseif ($responseCode === TransactionResponse::RESPONSE_CODE_PENDING) {
return static::STATUS_PENDIND;
} elseif ($responseCode !== null) {
return static::STATUS_FAILED;
}
}

/**
Expand All @@ -98,7 +107,8 @@ public function getTransactionStatus()
*/
public function getMessage()
{
// TODO.
// There are actually no messages in the notifications.
return '';
}

/**
Expand All @@ -112,4 +122,92 @@ public function sendData($data)
{
return $this;
}

/**
* The main target of the notificaiton: payment or customer.
*/
public function getEventTarget()
{
return $this->getParsedData()->getEventTarget();
}

/**
* The sub-target of the notificaiton.
*/
public function getEventSubtarget()
{
return $this->getParsedData()->getEventSubtarget();
}

/**
* The action against the target of the notificaito.
*/
public function getEventAction()
{
return $this->getParsedData()->getEventAction();
}

/**
* The UUID identifying this specific notification.
*/
public function getNotificationId()
{
return $this->getParsedData()->getNotificationId();
}

/**
* The UUID identifying the webhook being fired.
*/
public function getWebhookId()
{
return $this->getParsedData()->getWebhookId();
}

/**
* Optional notification payload.
*/
public function getPayload()
{
return $this->getParsedData()->getPayload();
}

/**
* @return int Raw response code
*/
public function getResponseCode()
{
if ($this->getEventTarget() === $this->getParsedData()::EVENT_TARGET_PAYMENT) {
return $this->getPayload()->getResponseCode();
}
}

/**
* @return string Raw response code
*/
public function getAuthCode()
{
if ($this->getEventTarget() === $this->getParsedData()::EVENT_TARGET_PAYMENT) {
return $this->getPayload()->getAuthCode();
}
}

/**
* @return string Raw AVS response code
*/
public function getAvsResponse()
{
if ($this->getEventTarget() === $this->getParsedData()::EVENT_TARGET_PAYMENT) {
return $this->getPayload()->getAvsResponse();
}
}

/**
* @return float authAmount, no currency, no stated units
*/
public function getAuthAmount()
{
if ($this->getEventTarget() === $this->getParsedData()::EVENT_TARGET_PAYMENT) {
return $this->getPayload()->getAuthAmount();
}
}
}

0 comments on commit 7be1f84

Please sign in to comment.