shop.balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

squareup.php (15012B)


      1 <?php
      2 
      3 class Squareup {
      4     private $session;
      5     private $url;
      6     private $config;
      7     private $log;
      8     private $customer;
      9     private $currency;
     10     private $registry;
     11 
     12     const API_URL = 'https://connect.squareup.com';
     13     const API_VERSION = 'v2';
     14     const ENDPOINT_ADD_CARD = 'customers/%s/cards';
     15     const ENDPOINT_AUTH = 'oauth2/authorize';
     16     const ENDPOINT_CAPTURE_TRANSACTION = 'locations/%s/transactions/%s/capture';
     17     const ENDPOINT_CUSTOMERS = 'customers';
     18     const ENDPOINT_DELETE_CARD = 'customers/%s/cards/%s';
     19     const ENDPOINT_GET_TRANSACTION = 'locations/%s/transactions/%s';
     20     const ENDPOINT_LOCATIONS = 'locations';
     21     const ENDPOINT_REFRESH_TOKEN = 'oauth2/clients/%s/access-token/renew';
     22     const ENDPOINT_REFUND_TRANSACTION = 'locations/%s/transactions/%s/refund';
     23     const ENDPOINT_TOKEN = 'oauth2/token';
     24     const ENDPOINT_TRANSACTIONS = 'locations/%s/transactions';
     25     const ENDPOINT_VOID_TRANSACTION = 'locations/%s/transactions/%s/void';
     26     const PAYMENT_FORM_URL = 'https://js.squareup.com/v2/paymentform';
     27     const SCOPE = 'MERCHANT_PROFILE_READ PAYMENTS_READ SETTLEMENTS_READ CUSTOMERS_READ CUSTOMERS_WRITE';
     28     const VIEW_TRANSACTION_URL = 'https://squareup.com/dashboard/sales/transactions/%s/by-unit/%s';
     29     const SQUARE_INTEGRATION_ID = 'sqi_65a5ac54459940e3600a8561829fd970';
     30 
     31     public function __construct($registry) {
     32         $this->session = $registry->get('session');
     33         $this->url = $registry->get('url');
     34         $this->config = $registry->get('config');
     35         $this->log = $registry->get('log');
     36         $this->customer = $registry->get('customer');
     37         $this->currency = $registry->get('currency');
     38         $this->registry = $registry;
     39     }
     40 
     41     public function api($request_data) {
     42         $url = self::API_URL;
     43 
     44         if (empty($request_data['no_version'])) {
     45             $url .= '/' . self::API_VERSION;
     46         }
     47 
     48         $url .= '/' . $request_data['endpoint'];
     49 
     50         $curl_options = array(
     51             CURLOPT_URL => $url,
     52             CURLOPT_RETURNTRANSFER => true
     53         );
     54 
     55         if (!empty($request_data['content_type'])) {
     56             $content_type = $request_data['content_type'];
     57         } else {
     58             $content_type = 'application/json';
     59         }
     60 
     61         // handle method and parameters
     62         if (isset($request_data['parameters']) && is_array($request_data['parameters']) && count($request_data['parameters'])) {
     63             $params = $this->encodeParameters($request_data['parameters'], $content_type);
     64         } else {
     65             $params = null;
     66         }
     67 
     68         switch ($request_data['method']) {
     69             case 'GET' :
     70                 $curl_options[CURLOPT_POST] = false;
     71 
     72                 if (is_string($params)) {
     73                     $curl_options[CURLOPT_URL] .= ((strpos($url, '?') === false) ? '?' : '&') . $params;
     74                 }
     75 
     76                 break;
     77             case 'POST' :
     78                 $curl_options[CURLOPT_POST] = true;
     79 
     80                 if ($params !== null) {
     81                     $curl_options[CURLOPT_POSTFIELDS] = $params;
     82                 }
     83 
     84                 break;
     85             default : 
     86                 $curl_options[CURLOPT_CUSTOMREQUEST] = $request_data['method'];
     87 
     88                 if ($params !== null) {
     89                     $curl_options[CURLOPT_POSTFIELDS] = $params;
     90                 }
     91 
     92                 break;
     93         }
     94 
     95         // handle headers
     96         $added_headers = array();
     97 
     98         if (!empty($request_data['auth_type'])) {
     99             if (empty($request_data['token'])) {
    100                 if ($this->config->get('payment_squareup_enable_sandbox')) {
    101                     $token = $this->config->get('payment_squareup_sandbox_token');
    102                 } else {
    103                     $token = $this->config->get('payment_squareup_access_token');
    104                 }
    105             } else {
    106                 // custom token trumps sandbox/regular one
    107                 $token = $request_data['token'];
    108             }
    109             
    110             $added_headers[] = 'Authorization: ' . $request_data['auth_type'] . ' ' . $token;
    111         }
    112 
    113         if (!is_array($params)) {
    114             // curl automatically adds Content-Type: multipart/form-data when we provide an array
    115             $added_headers[] = 'Content-Type: ' . $content_type;
    116         }
    117 
    118         if (isset($request_data['headers']) && is_array($request_data['headers'])) {
    119             $curl_options[CURLOPT_HTTPHEADER] = array_merge($added_headers, $request_data['headers']);
    120         } else {
    121             $curl_options[CURLOPT_HTTPHEADER] = $added_headers;
    122         }
    123 
    124         $this->debug("SQUAREUP DEBUG START...");
    125         $this->debug("SQUAREUP ENDPOINT: " . $curl_options[CURLOPT_URL]);
    126         $this->debug("SQUAREUP HEADERS: " . print_r($curl_options[CURLOPT_HTTPHEADER], true));
    127         $this->debug("SQUAREUP PARAMS: " . $params);
    128 
    129         // Fire off the request
    130         $ch = curl_init();
    131         curl_setopt_array($ch, $curl_options);
    132         $result = curl_exec($ch);
    133 
    134         if ($result) {
    135             $this->debug("SQUAREUP RESULT: " . $result);
    136 
    137             curl_close($ch);
    138 
    139             $return = json_decode($result, true);
    140 
    141             if (!empty($return['errors'])) {
    142                 throw new \Squareup\Exception($this->registry, $return['errors']);
    143             } else {
    144                 return $return;
    145             }
    146         } else {
    147             $info = curl_getinfo($ch);
    148 
    149             curl_close($ch);
    150 
    151             throw new \Squareup\Exception($this->registry, "CURL error. Info: " . print_r($info, true), true);
    152         }
    153     }
    154 
    155     public function verifyToken($access_token) {
    156         try {
    157             $request_data = array(
    158                 'method' => 'GET',
    159                 'endpoint' => self::ENDPOINT_LOCATIONS,
    160                 'auth_type' => 'Bearer',
    161                 'token' => $access_token
    162             );
    163 
    164             $this->api($request_data);
    165         } catch (\Squareup\Exception $e) {
    166             if ($e->isAccessTokenRevoked() || $e->isAccessTokenExpired()) {
    167                 return false;
    168             }
    169 
    170             // In case some other error occurred
    171             throw $e;
    172         }
    173 
    174         return true;
    175     }
    176 
    177     public function authLink($client_id) {
    178         $state = $this->authState();
    179 
    180         $redirect_uri = str_replace('&amp;', '&', $this->url->link('extension/payment/squareup/oauth_callback', 'user_token=' . $this->session->data['user_token'], true));
    181 
    182         $this->session->data['payment_squareup_oauth_redirect'] = $redirect_uri;
    183 
    184         $params = array(
    185             'client_id' => $client_id,
    186             'response_type' => 'code',
    187             'scope' => self::SCOPE,
    188             'locale' => 'en-US',
    189             'session' => 'false',
    190             'state' => $state,
    191             'redirect_uri' => $redirect_uri
    192         );
    193 
    194         return self::API_URL . '/' . self::ENDPOINT_AUTH . '?' . http_build_query($params);
    195     }
    196 
    197     public function fetchLocations($access_token, &$first_location_id) {
    198         $request_data = array(
    199             'method' => 'GET',
    200             'endpoint' => self::ENDPOINT_LOCATIONS,
    201             'auth_type' => 'Bearer',
    202             'token' => $access_token
    203         );
    204 
    205         $api_result = $this->api($request_data);
    206 
    207         $locations = array_filter($api_result['locations'], array($this, 'filterLocation'));
    208 
    209         if (!empty($locations)) {
    210             $first_location = current($locations);
    211             $first_location_id = $first_location['id'];
    212         } else {
    213             $first_location_id = null;
    214         }
    215 
    216         return $locations;
    217     }
    218 
    219     public function exchangeCodeForAccessToken($code) {
    220         $request_data = array(
    221             'method' => 'POST',
    222             'endpoint' => self::ENDPOINT_TOKEN,
    223             'no_version' => true,
    224             'parameters' => array(
    225                 'client_id' => $this->config->get('payment_squareup_client_id'),
    226                 'client_secret' => $this->config->get('payment_squareup_client_secret'),
    227                 'redirect_uri' => $this->session->data['payment_squareup_oauth_redirect'],
    228                 'code' => $code
    229             )
    230         );
    231 
    232         return $this->api($request_data);
    233     }
    234 
    235     public function debug($text) {
    236         if ($this->config->get('payment_squareup_debug')) {
    237             $this->log->write($text);
    238         }
    239     }
    240 
    241     public function refreshToken() {
    242         $request_data = array(
    243             'method' => 'POST',
    244             'endpoint' => sprintf(self::ENDPOINT_REFRESH_TOKEN, $this->config->get('payment_squareup_client_id')),
    245             'no_version' => true,
    246             'auth_type' => 'Client',
    247             'token' => $this->config->get('payment_squareup_client_secret'),
    248             'parameters' => array(
    249                 'access_token' => $this->config->get('payment_squareup_access_token')
    250             )
    251         );
    252 
    253         return $this->api($request_data);
    254     }
    255 
    256     public function addCard($square_customer_id, $card_data) {
    257         $request_data = array(
    258             'method' => 'POST',
    259             'endpoint' => sprintf(self::ENDPOINT_ADD_CARD, $square_customer_id),
    260             'auth_type' => 'Bearer',
    261             'parameters' => $card_data
    262         );
    263 
    264         $result = $this->api($request_data);
    265 
    266         return array(
    267             'id' => $result['card']['id'],
    268             'card_brand' => $result['card']['card_brand'],
    269             'last_4' => $result['card']['last_4']
    270         );
    271     }
    272 
    273     public function deleteCard($square_customer_id, $card) {
    274         $request_data = array(
    275             'method' => 'DELETE',
    276             'endpoint' => sprintf(self::ENDPOINT_DELETE_CARD, $square_customer_id, $card),
    277             'auth_type' => 'Bearer'
    278         );
    279 
    280         return $this->api($request_data);
    281     }
    282 
    283     public function addLoggedInCustomer() {
    284         $request_data = array(
    285             'method' => 'POST',
    286             'endpoint' => self::ENDPOINT_CUSTOMERS,
    287             'auth_type' => 'Bearer',
    288             'parameters' => array(
    289                 'given_name' => $this->customer->getFirstName(),
    290                 'family_name' => $this->customer->getLastName(),
    291                 'email_address' => $this->customer->getEmail(),
    292                 'phone_number' => $this->customer->getTelephone(),
    293                 'reference_id' => $this->customer->getId()
    294             )
    295         );
    296 
    297         $result = $this->api($request_data);
    298 
    299         return array(
    300             'customer_id' => $this->customer->getId(),
    301             'sandbox' => $this->config->get('payment_squareup_enable_sandbox'),
    302             'square_customer_id' => $result['customer']['id']
    303         );
    304     }
    305 
    306     public function addTransaction($data) {
    307         if ($this->config->get('payment_squareup_enable_sandbox')) {
    308             $location_id = $this->config->get('payment_squareup_sandbox_location_id');
    309         } else {
    310             $location_id = $this->config->get('payment_squareup_location_id');
    311         }
    312 
    313         $request_data = array(
    314             'method' => 'POST',
    315             'endpoint' => sprintf(self::ENDPOINT_TRANSACTIONS, $location_id),
    316             'auth_type' => 'Bearer',
    317             'parameters' => $data
    318         );
    319 
    320         $result = $this->api($request_data);
    321 
    322         return $result['transaction'];
    323     }
    324 
    325     public function getTransaction($location_id, $transaction_id) {
    326         $request_data = array(
    327             'method' => 'GET',
    328             'endpoint' => sprintf(self::ENDPOINT_GET_TRANSACTION, $location_id, $transaction_id),
    329             'auth_type' => 'Bearer'
    330         );
    331 
    332         $result = $this->api($request_data);
    333 
    334         return $result['transaction'];
    335     }
    336 
    337     public function captureTransaction($location_id, $transaction_id) {
    338         $request_data = array(
    339             'method' => 'POST',
    340             'endpoint' => sprintf(self::ENDPOINT_CAPTURE_TRANSACTION, $location_id, $transaction_id),
    341             'auth_type' => 'Bearer'
    342         );
    343 
    344         $this->api($request_data);
    345 
    346         return $this->getTransaction($location_id, $transaction_id);
    347     }
    348 
    349     public function voidTransaction($location_id, $transaction_id) {
    350         $request_data = array(
    351             'method' => 'POST',
    352             'endpoint' => sprintf(self::ENDPOINT_VOID_TRANSACTION, $location_id, $transaction_id),
    353             'auth_type' => 'Bearer'
    354         );
    355 
    356         $this->api($request_data);
    357 
    358         return $this->getTransaction($location_id, $transaction_id);
    359     }
    360 
    361     public function refundTransaction($location_id, $transaction_id, $reason, $amount, $currency, $tender_id) {
    362         $request_data = array(
    363             'method' => 'POST',
    364             'endpoint' => sprintf(self::ENDPOINT_REFUND_TRANSACTION, $location_id, $transaction_id),
    365             'auth_type' => 'Bearer',
    366             'parameters' => array(
    367                 'idempotency_key' => uniqid(),
    368                 'tender_id' => $tender_id,
    369                 'reason' => $reason,
    370                 'amount_money' => array(
    371                     'amount' => $this->lowestDenomination($amount, $currency),
    372                     'currency' => $currency
    373                 )
    374             )
    375         );
    376 
    377         $this->api($request_data);
    378 
    379         return $this->getTransaction($location_id, $transaction_id);
    380     }
    381 
    382     public function lowestDenomination($value, $currency) {
    383         $power = $this->currency->getDecimalPlace($currency);
    384 
    385         $value = (float)$value;
    386 
    387         return (int)($value * pow(10, $power));
    388     }
    389 
    390     public function standardDenomination($value, $currency) {
    391         $power = $this->currency->getDecimalPlace($currency);
    392 
    393         $value = (int)$value;
    394 
    395         return (float)($value / pow(10, $power));
    396     }
    397 
    398     protected function filterLocation($location) {
    399         if (empty($location['capabilities'])) {
    400             return false;
    401         }
    402 
    403         return in_array('CREDIT_CARD_PROCESSING', $location['capabilities']);
    404     }
    405 
    406     protected function encodeParameters($params, $content_type) {
    407         switch ($content_type) {
    408             case 'application/json' :
    409                 return json_encode($params);
    410             case 'application/x-www-form-urlencoded' :
    411                 return http_build_query($params);
    412             default :
    413             case 'multipart/form-data' :
    414                 // curl will handle the params as multipart form data if we just leave it as an array
    415                 return $params;
    416         }
    417     }
    418 
    419     protected function authState() {
    420         if (!isset($this->session->data['payment_squareup_oauth_state'])) {
    421             $this->session->data['payment_squareup_oauth_state'] = bin2hex(openssl_random_pseudo_bytes(32));
    422         }
    423 
    424         return $this->session->data['payment_squareup_oauth_state'];
    425     }
    426 }