Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Transaction Reporting functionality #88

Merged
merged 11 commits into from
May 15, 2020
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
CHANGELOG
=========

1.13.0 (XXXX-XX-XX)
-------------------

PatrickCronin marked this conversation as resolved.
Show resolved Hide resolved
* Added support for the Report Transactions API. We encourage the use of this
API as we use data received through this channel to continually improve the
accuracy of our fraud detection algorithms.

1.12.0 (2020-04-06)
-------------------

Expand Down
79 changes: 76 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ Page](https://maxmind.github.io/minfraud-api-php/) under the "API" tab.

## Usage ##

To use this API, create a new `\MaxMind\MinFraud` object. The constructor
This library provides access to both the [minFraud (Score, Insights and
Factors)](https://dev.maxmind.com/minfraud/)
and [Report Transaction](https://dev.maxmind.com/minfraud/report-transaction/) APIs.

### minFraud API ###

To use the MinFraud API, create a new `\MaxMind\MinFraud` object. The constructor
takes your MaxMind account ID, license key, and an optional options array as
arguments. This object is immutable. You then build up the request using the
`->with*` methods as shown below. Each method call returns a new object. The
Expand All @@ -98,7 +104,7 @@ thrown.

See the API documentation for more details.

### Exceptions ###
#### minFraud Exceptions ####

All externally visible exceptions are in the `\MaxMind\Exception` namespace.
The possible exceptions are:
Expand All @@ -123,7 +129,7 @@ The possible exceptions are:
serves as the base class for the above exceptions.


## Example
#### minFraud Example ####

```php
<?php
Expand Down Expand Up @@ -243,6 +249,73 @@ foreach ($scoreResponse->warnings as $warning) {
}
```

### Report Transactions API ###

MaxMind encourages the use of this API as data received through this channel is
used to continually improve the accuracy of our fraud detection algorithms.

To use the Report Transactions API, create a new
`\MaxMind\MinFraud\ReportTransaction` object. The constructor takes your MaxMind
account ID, license key, and an optional options array as arguments. This object
is immutable. You then send one or more reports using the `->report` method as
shown below.

If there is a validation error in the data passed to the `->report` method, a
`\MaxMind\Exception` will be thrown. This validation can be disabled by
setting `validateInput` to `false` in the options array for
`\MaxMind\MinFraud\ReportTransaction`, but it is recommended that you keep it on
at least through development as it will help ensure that you are sending valid
data to the web service.

If the report is successful, nothing is returned. If the report fails, an
exception with be thrown.

See the API documentation for more details.

#### Report Transaction Exceptions ####

All externally visible exceptions are in the `\MaxMind\Exception` namespace.
The possible exceptions are:

* `InvalidInputException` - This will be thrown when the `->report()` method is
called with invalid input data or when the required `ip_address` or `tag`
fields are missing.
* `AuthenticationException` - This will be thrown on calling `->report()`,
when the server is unable to authenticate the request, e.g., if the license
key or account ID is invalid.
* `InvalidRequestException` - This will be thrown on calling `->report()` when
the server rejects the request for another reason such as invalid JSON in the
POST.
* `HttpException` - This will be thrown on calling `->report()` when an
unexpected HTTP error occurs such as a firewall interfering with the request
to the server.
* `WebServiceException` - This will be thrown on calling `->report()` when some
other error occurs. This also serves as the base class for the above
exceptions.

#### Report Transaction Example ####

```php
<?php
require_once 'vendor/autoload.php';
use MaxMind\MinFraud\ReportTransaction;

# The constructor for ReportTransaction takes your account ID, your license key,
# and optionally an array of options.
$rt = new ReportTransaction(1, 'ABCD567890');

$rt->report(
'ip_address' => '81.2.69.160',
'tag' => 'chargeback',
PatrickCronin marked this conversation as resolved.
Show resolved Hide resolved
'chargeback_code' => 'UA02',
'minfraud_id' => '26ae87e4-5112-4f76-b0f7-4132d45d72b2',
'maxmind_id' => 'aBcDeFgH',
'notes' => 'Found due to non-existent shipping address',
'transaction_id' => 'cart123456789',
);

```

## Support ##

Please report all issues with this code using the
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"php": ">=5.6",
"ext-json": "*",
"geoip2/geoip2": "^2.10",
"maxmind/web-service-common": "^0.6",
"maxmind/web-service-common": "^0.7",
"respect/validation": "~1.0"
},
"require-dev": {
Expand Down
4 changes: 2 additions & 2 deletions dev-bin/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fi

version="${BASH_REMATCH[1]}"
date="${BASH_REMATCH[2]}"
notes="$(echo "${BASH_REMATCH[3]}" | sed -n -e '/^[0-9]\+\.[0-9]\+\.[0-9]\+/,$!p')"
notes="$(echo "${BASH_REMATCH[3]}" | sed -n -E '/^[0-9]+\.[0-9]+\.[0-9]+/,$!p')"

if [[ "$date" -ne $(date +"%Y-%m-%d") ]]; then
echo "$date is not today!"
Expand All @@ -44,7 +44,7 @@ fi
php composer.phar self-update
php composer.phar update --no-dev

perl -pi -e "s/(?<=const VERSION = ').+?(?=';)/$tag/g" src/MinFraud.php
perl -pi -e "s/(?<=const VERSION = ').+?(?=';)/$tag/g" src/MinFraud/ServiceClient.php

if [ ! -f box.phar ]; then
wget -O box.phar "https://github.com/box-project/box2/releases/download/2.6.1/box-2.6.1.phar"
Expand Down
110 changes: 22 additions & 88 deletions src/MinFraud.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
use MaxMind\Exception\InvalidRequestException;
use MaxMind\Exception\WebServiceException;
use MaxMind\MinFraud\Validation;
use MaxMind\WebService\Client;
use Respect\Validation\Exceptions\ValidationException;

/**
* This class provides a client API for accessing MaxMind minFraud Score
* and Insights.
* This class provides a client API for accessing MaxMind minFraud Score,
* Insights and Factors.
*
* ## Usage ##
*
Expand All @@ -36,17 +34,10 @@
*
* If the request fails, an exception is thrown.
*/
class MinFraud
class MinFraud extends MinFraud\ServiceClient
{
const VERSION = 'v1.12.0';
PatrickCronin marked this conversation as resolved.
Show resolved Hide resolved

private $client;
private static $host = 'minfraud.maxmind.com';

private static $basePath = '/minfraud/v2.0/';
private $content;
private $locales;
private $validateInput = true;

/**
* @param int $accountId Your MaxMind account ID
Expand Down Expand Up @@ -79,15 +70,7 @@ public function __construct(
$this->locales = ['en'];
}

if (isset($options['validateInput'])) {
$this->validateInput = $options['validateInput'];
}

if (!isset($options['host'])) {
$options['host'] = self::$host;
}
$options['userAgent'] = $this->userAgent();
$this->client = new Client($accountId, $licenseKey, $options);
parent::__construct($accountId, $licenseKey, $options);
}

/**
Expand Down Expand Up @@ -303,6 +286,24 @@ public function withShoppingCartItem($values)
return $new;
}

/**
* @param string $className The name of the class (but not the namespace)
* @param string $key The key in the transaction array to set
* @param array $values The values to validate
*
* @throws InvalidInputException when $values does not validate
*
* @return MinFraud
*/
private function validateAndAdd($className, $key, $values)
{
$values = $this->cleanAndValidate($className, $values);
$new = clone $this;
$new->content[$key] = $values;

return $new;
}

/**
* This method performs a minFraud Score lookup using the request data in
* the current object and returns a model object for minFraud Score.
Expand Down Expand Up @@ -398,71 +399,4 @@ private function post($service)
$this->locales
);
}

/**
* @return string the prefix for the User-Agent header
*/
private function userAgent()
{
return 'minFraud-API/' . self::VERSION;
}

/**
* @param string $className The name of the class (but not the namespace)
* @param string $key The key in the transaction array to set
* @param array $values The values to validate
*
* @throws InvalidInputException when $values does not validate
*
* @return MinFraud
*/
private function validateAndAdd($className, $key, $values)
{
$values = $this->cleanAndValidate($className, $values);
$new = clone $this;
$new->content[$key] = $values;

return $new;
}

/**
* @param string $className The name of the class (but not the namespace)
* @param array $values The values to validate
*
* @throws InvalidInputException when $values does not validate
*
* @return array The cleaned values
*/
private function cleanAndValidate($className, $values)
{
$values = $this->clean($values);

if (!$this->validateInput) {
return $values;
}

$class = '\\MaxMind\\MinFraud\\Validation\\Rules\\' . $className;
$validator = new $class();
try {
$validator->check($values);
} catch (ValidationException $exception) {
throw new InvalidInputException($exception->getMessage(), $exception->getCode());
}

return $values;
}

private function clean($array)
{
$cleaned = [];
foreach ($array as $key => $value) {
if (\is_array($value)) {
$cleaned[$key] = $this->clean($array[$key]);
} elseif ($array[$key] !== null) {
$cleaned[$key] = $array[$key];
}
}

return $cleaned;
}
}
62 changes: 62 additions & 0 deletions src/MinFraud/ReportTransaction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace MaxMind\MinFraud;

use MaxMind\Exception\InvalidInputException;

class ReportTransaction extends ServiceClient
{
/**
* @param int $accountId Your MaxMind account ID
* @param string $licenseKey Your MaxMind license key
* @param array $options An array of options. Possible keys:
*
* * `host` - The host to use when connecting to the web service.
* * `userAgent` - The prefix for the User-Agent header to use in the
* request.
* * `caBundle` - The bundle of CA root certificates to use in the request.
* * `connectTimeout` - The connect timeout to use for the request.
* * `timeout` - The timeout to use for the request.
* * `proxy` - The HTTP proxy to use. May include a schema, port,
* username, and password, e.g., `http://username:password@127.0.0.1:10`.
* * `validateInput` - Default is `true`. Determines whether values passed
* to the `with*()` methods are validated. It is recommended that you
* leave validation on while developing and only (optionally) disable it
* before deployment.
*/
public function __construct(
$accountId,
$licenseKey,
$options = []
) {
parent::__construct($accountId, $licenseKey, $options);
}

/**
* @param array $values the transaction parameters
*
* @throws InvalidInputException when the request has missing or invalid
* data
* @throws AuthenticationException when there is an issue authenticating the
* request
* @throws InvalidRequestException when the request is invalid for some
* other reason, e.g., invalid JSON in the POST.
* @throws HttpException when an unexpected HTTP error occurs
* @throws WebServiceException when some other error occurs. This also
* serves as the base class for the above exceptions.
*/
public function report($values)
{
$values = $this->cleanAndValidate('TransactionReport', $values);

if (!isset($values['ip_address'])) {
throw new InvalidInputException('Key ip_address must be present in request');
}
if (!isset($values['tag'])) {
throw new InvalidInputException('Key tag must be present in request');
}

$url = self::$basePath . 'transactions/report';
$this->client->post('ReportTransaction', $url, $values);
}
}
Loading