Avatax.php in Drupal Commerce Connector for AvaTax 7.5
Defines a class for consuming the Avatax API.
File
lib/Avatax.phpView source
<?php
/**
* @file
* Defines a class for consuming the Avatax API.
*/
/**
* Defines the Avatax class.
*
* A modern PHP library would namespace its classes under a package name, which
* in this case would mean using the Percolate namespace and instantiating new
* objects of this class via:
*
* $avatax = new Avalara\Avatax(...);
*
* Unfortunately, Drupal 7 does not support namespaces in its autoloader, as it
* maintains compatibility with previous versions of PHP that did not support
* namespaces. Thus this library does not currently use a namespace.
*/
class Avatax {
// Define properties for storing API credentials.
protected $apiKey;
// The API mode (dev|prod).
protected $apiMode;
// Reference the logger callable.
protected $logger;
// Manage a single cURL handle used to submit API requests.
protected $ch;
// Stores the HTTP headers.
protected $headers;
/**
* Initializes the API credential properties and cURL handle.
* @param string $apiKey
* The API key defined that is used to authenticate against the API.
* @param string $apiMode
* The API mode (dev|prod), used to determine the endpoint to call.
* @param string $logger
* A callable used to log API request / response messages. Leave empty if
* logging is not needed.
* @param array $headers
* Allow specifying additional HTTP headers that are going to be sent.
*/
public function __construct($apiKey, $apiMode = 'dev', $logger = NULL, $headers = array()) {
// Initialize the API credential properties.
$this->apiKey = $apiKey;
$this->apiMode = $apiMode;
$this->logger = $logger;
$this->headers = array_merge($headers, array(
'Authorization' => 'Basic ' . $apiKey,
'Content-Type' => 'application/json',
'x-Avalara-UID' => 'a0o33000003waOC',
));
// Initialize the cURL handle.
$this->ch = curl_init();
$this
->setDefaultCurlOptions();
}
/**
* Returns the HTTP headers.
*
* @return array
* The HTTP headers used when submitting API requests.
*/
public function httpHeaders() {
return $this->headers;
}
/**
* Gets the API mode.
*
* @return string
* The API mode (dev|prod).
*/
public function getApiMode() {
return $this->apiMode;
}
/**
* Gets the API url.
*
* @return string
* The API url.
*/
public function getApiUrl() {
if ($this
->getApiMode() == 'dev') {
return 'https://sandbox-rest.avatax.com/api/v2/';
}
else {
return 'https://rest.avatax.com/api/v2/';
}
}
/**
* Returns the object's API key.
*
* @return string
* The API key.
*/
public function getApiKey() {
return $this->apiKey;
}
/**
* Closes the cURL handle when the object is destroyed.
*/
public function __destruct() {
if (is_resource($this->ch)) {
curl_close($this->ch);
}
}
/**
* Tests connectivity and version of the service.
*/
public function ping() {
return $this
->doRequest('GET', 'utilities/ping');
}
/**
* Retrieve geolocation information for a specified address.
*
* @param array $parameters
* An associate array of POST body parameters containing the address to
* geolocate.
* @return array
* See https://developer.avalara.com/api-reference/avatax/rest/v2/models/AddressResolutionModel/
*/
public function addressesResolve(array $parameters) {
$parameters += array(
'textCase' => 'Mixed',
);
return $this
->doRequest('POST', 'addresses/resolve', $parameters);
}
/**
* Create a new transaction.
*
* @param string[] $parameters
* An associative array of POST body parameters to be sent that should at
* least contain the companycode, the code, the date, and the customerCode.
*/
public function transactionsCreate($parameters) {
return $this
->doRequest('POST', "transactions/create", $parameters);
}
/**
* Correct a previously created transaction.
*
* @param string $companyCode
* The company code of the company that recorded these transactions.
*
* @param string $transactionCode
* The transaction code to adjust.
*
* @param string[] $parameters
* An associative array of POST body parameters that should contain the
* adjustmentReason & adjustmentDescription.
*
* @return array
*/
public function transactionsAdjust($companyCode, $transactionCode, $parameters) {
return $this
->doRequest('POST', "companies/{$companyCode}/transactions/{$transactionCode}/adjust", $parameters);
}
/**
* Void a transaction
*
* @param string $companyCode
* The company code of the company that recorded these transactions.
*
* @param string $transactionCode
* The transaction code to void.
*
* @param string[] $parameters
* An associative array of POST body parameters that should contain the
* code (the reason for voiding or cancelling this transaction).
*
* @return array
*
*/
public function transactionsVoid($companyCode, $transactionCode, $parameters) {
return $this
->doRequest('POST', "companies/{$companyCode}/transactions/{$transactionCode}/void", $parameters);
}
/**
* Commit a transaction for reporting.
*
* @param string $companyCode
* The company code of the company that recorded these transactions.
*
* @param string $transactionCode
* The transaction code to commit.
*
* @return array
* An associative array containing the id number of the transaction, the
* code, the companyId, date etc.
*/
public function transactionsCommit($companyCode, $transactionCode) {
return $this
->doRequest('POST', "companies/{$companyCode}/transactions/{$transactionCode}/commit", array(
'commit' => TRUE,
));
}
/**
* Sets the default cURL options.
*/
public function setDefaultCurlOptions() {
$headers = array();
foreach ($this
->httpHeaders() as $key => $value) {
$headers[] = "{$key}: {$value}";
}
curl_setopt($this->ch, CURLOPT_HEADER, FALSE);
curl_setopt($this->ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, TRUE);
curl_setopt($this->ch, CURLOPT_VERBOSE, FALSE);
curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 180);
}
/**
* Send a message to the logger.
*
* @param string $message
* The message to log.
* @param $variables
* Array of variables to replace in the message on display or
* NULL if message is already translated or not possible to
* translate.
* @param int $severity
* The severity of the message; one of the following values:
* - WATCHDOG_EMERGENCY: Emergency, system is unusable.
* - WATCHDOG_ALERT: Alert, action must be taken immediately.
* - WATCHDOG_CRITICAL: Critical conditions.
* - WATCHDOG_ERROR: Error conditions.
* - WATCHDOG_WARNING: Warning conditions.
* - WATCHDOG_NOTICE: (default) Normal but significant conditions.
* - WATCHDOG_INFO: Informational messages.
* - WATCHDOG_DEBUG: Debug-level messages.
*
* @see http://www.faqs.org/rfcs/rfc3164.html
*/
public function logMessage($message, $variables = array(), $severity = WATCHDOG_NOTICE) {
if (is_callable($this->logger)) {
call_user_func_array($this->logger, array(
'commerce_avatax',
$message,
$variables,
$severity,
));
}
}
/**
* Performs a request.
*
* @param string $method
* The HTTP method to use. One of: 'GET', 'POST', 'PUT', 'DELETE'.
* @param string $path
* The remote path. The base URL will be automatically appended.
* @param array $fields
* An array of fields to include with the request. Optional.
*
* @return array
* An array with the 'success' boolean and the result. If 'success' is FALSE
* the result will be an error message. Otherwise it will be an array
* of returned data.
*/
protected function doRequest($method, $path, array $fields = array()) {
$return = array();
$url = $this
->getApiUrl() . $path;
// Set the request URL and method.
curl_setopt($this->ch, CURLOPT_URL, $url);
curl_setopt($this->ch, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $method);
if (!empty($fields)) {
// JSON encode the fields and set them to the request body.
$fields = json_encode($fields);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $fields);
// Log the API request with the JSON encoded fields.
}
$result = curl_exec($this->ch);
$response_code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
$success = in_array($response_code, array(
200,
201,
));
// Log information about the request.
$this
->logMessage('Request info: !url !headers !response !meta', array(
'!url' => "<pre>URL : {$method} {$url}</pre>",
'!headers' => "<pre>Request Headers:\n" . var_export(curl_getinfo($this->ch, CURLINFO_HEADER_OUT), TRUE) . '</pre>',
'!response' => "<pre>Response:\n" . var_export($result, TRUE) . '</pre>',
'!meta' => "<pre>Response Meta:\n" . var_export(curl_getinfo($this->ch), TRUE) . '</pre>',
));
if (!$success) {
// Return the error message if it exists.
if (!empty($result)) {
$decoded_result = json_decode($result, TRUE);
// Return the error message if it's there.
if (isset($decoded_result['error'])) {
$return['error'] = $decoded_result['error'];
}
}
$result = 'Error ' . $response_code;
}
elseif ($success && !empty($result)) {
$result = json_decode($result, TRUE);
}
$return += array(
'success' => $success,
'result' => $result,
'response_code' => $response_code,
);
return $return;
}
}