PluginProbe
Route ‑ Shipping Protection / 2.2.6
Route ‑ Shipping Protection v2.2.6
2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.2.4 2.2.5 2.2.6 2.2.8 2.2.9 2.3.0 2.3.1 2.3.2 2.3.3 All 151 releases
routeapp / includes / class-routeapp-api-client.php

class-routeapp-api-client.php in Route ‑ Shipping Protection 2.2.6, at includes/class-routeapp-api-client.php

585 lines 17.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WooCommerce Routeapp API Client Class
4 *
5 * @link https://route.com/
6 * @since 1.0.0
7 *
8 * @package Routeapp
9 * @subpackage Routeapp/includes
10 */
11
12 class Routeapp_API_Client
13 {
14 /**
15 * API base endpoint v1
16 */
17 const API_ENDPOINT_V1 = 'https://api.route.com/v1/';
18
19 /**
20 * API stage base endpoint v1
21 */
22 const API_STAGE_ENDPOINT_V1 = 'https://api-stage.route.com/v1/';
23
24 /**
25 * API base endpoint v2
26 */
27 const API_ENDPOINT_V2 = 'https://api.route.com/v2/';
28
29 /**
30 * API stage base endpoint v2
31 */
32 const API_STAGE_ENDPOINT_V2 = 'https://api-stage.route.com/v2/';
33
34 /**
35 * Merchant ID Option name
36 */
37 const ROUTEAPP_MERCHANT_ID = 'routeapp_merchant_id';
38
39 /**
40 * The v1 API URL
41 * @var string
42 */
43 private $_api_url;
44
45 /**
46 * The v2 API URL
47 * @var string
48 */
49 private $_api_url_v2;
50
51 /**
52 * The WooCommerce Merchant Key
53 * @var string
54 */
55 private $_public_token;
56
57 /**
58 * The WooCommerce Merchant Key
59 * @var string
60 */
61 private $_secret_token;
62
63
64 /**
65 * Merchant
66 */
67 private $_merchant;
68
69 /**
70 * Data used for API Call
71 * @var array
72 */
73 protected $_extraData = [];
74
75 /**
76 * Cache API calls
77 */
78 private $_cachedApiCallsSessionKey = 'route_get_quote';
79
80 private static $instances = [];
81
82 /**
83 * Default contructor
84 * @param string $public_token The consumer key
85 * @param string $secret_token The consumer key
86 */
87 public function __construct($public_token = null, $secret_token = null)
88 {
89 $this->set_public_token($public_token);
90 $this->set_secret_token($secret_token);
91
92 $custom_env = getenv('ROUTEAPP_ENVIRONMENT_ENDPOINT');
93 if (is_null($custom_env) || !$custom_env) {
94 $custom_env = isset($_SERVER['ROUTEAPP_ENVIRONMENT_ENDPOINT']) ? $_SERVER['ROUTEAPP_ENVIRONMENT_ENDPOINT'] : '';
95 }
96 if ($custom_env == 'stage') {
97 $this->_api_url = rtrim($this->_api_url, '/') . self::API_STAGE_ENDPOINT_V1;
98 $this->_api_url_v2 = rtrim($this->_api_url_v2, '/') . self::API_STAGE_ENDPOINT_V2;
99 } else {
100 $this->_api_url = rtrim($this->_api_url, '/') . self::API_ENDPOINT_V1;
101 $this->_api_url_v2 = rtrim($this->_api_url_v2, '/') . self::API_ENDPOINT_V2;
102 }
103 }
104
105 /**
106 * Singletons should not be cloneable.
107 */
108 protected function __clone()
109 {}
110
111 public static function getInstance()
112 {
113 $cls = static::class;
114 if (!isset(static::$instances[$cls])) {
115 static::$instances[$cls] = new static;
116 }
117 return static::$instances[$cls];
118 }
119
120 /**
121 * Set the public token
122 * @param string $token
123 */
124 public function set_public_token($token)
125 {
126 $this->_public_token = $token;
127 }
128
129 /**
130 * Set the secret token
131 * @param string $token
132 */
133 public function set_secret_token($token)
134 {
135 $this->_secret_token = $token;
136 }
137
138 /**
139 * Get the public token
140 * @return string string
141 */
142 public function get_public_token()
143 {
144 return !empty($this->_public_token) ? $this->_public_token : get_option('routeapp_public_token');
145 }
146
147 public function get_cache_api_session_key()
148 {
149 return $this->_cachedApiCallsSessionKey;
150 }
151
152 /**
153 * Get the secret token
154 * @return string string
155 */
156 public function get_secret_token()
157 {
158 return !empty($this->_secret_token) ? $this->_secret_token : get_option('routeapp_secret_token');
159 }
160
161 /**
162 * Get the user token
163 * @return string string
164 */
165 public function get_user_token()
166 {
167 return get_option('routeapp_user_token');
168 }
169 /**
170 * Get the user id
171 * @return string string
172 */
173 public function get_user_id()
174 {
175 return get_option('routeapp_user_id');
176 }
177
178 /**
179 * Get current quote price based on subtotal
180 * @param $cartRef
181 * @param $cartTotal
182 * @param $currency
183 * @param $cartItems
184 * @return array|mixed
185 */
186 public function get_quote($cartRef, $cartTotal, $currency, $cartItems)
187 {
188 $currency = !$currency ? get_woocommerce_currency() : $currency;
189 $cartTotal = !is_null($cartTotal) && $cartTotal > 0 ? $cartTotal : 0;
190 $merchant_id = $this->get_merchant_id();
191
192 //empty subtotal or merchant_id just return zero
193 if ($cartTotal==0 || !$merchant_id) return ['body' => json_encode(['premium' => ['amount' => '0']])];
194
195 //check values on cache
196 $cached = false;
197 $key = $this->get_cache_api_session_key() . '-' . $cartRef;
198 if (WC()->session) {
199 $cached = WC()->session->get($key);
200 }
201 if ($cached) {
202 if (time() - $cached['createdAt'] > 1800) {
203 //if creation date is more than 30 minutes, we unset it
204 WC()->session->__unset($key);
205 } else {
206 return $cached['result'];
207 }
208 }
209
210 $cached['createdAt'] = time();
211 $cached['result'] = $this->_make_private_api_call('quotes', array(
212 'merchant_id' => $merchant_id,
213 'cart' => [
214 'cart_ref' => strval($cartRef),
215 'covered' => [
216 'currency' => strval($currency),
217 'amount' => strval($cartTotal)
218 ],
219 'cart_items' => $cartItems,
220 ],
221 ), 'POST', 'v2');
222 if (WC()->session) {
223 WC()->session->set($key, $cached);
224 $lastCalledMade = $key. '-latest';
225 WC()->session->set($lastCalledMade, $cached['result']);
226 }
227 return $cached['result'];
228 }
229
230 /**
231 * Create the order shipment, currently only status update suported by API
232 * @param integer $tracking_id
233 * @param array $data
234 * @return mixed|json string
235 */
236 public function create_shipment($tracking_id, $data = array())
237 {
238 if (empty($tracking_id)) return false;
239 return $this->_make_private_api_call('shipments', array(
240 'tracking_number' => $this->sanitize_value($tracking_id),
241 'source_order_id' => $data['source_order_id'],
242 'source_product_ids' => $data['source_product_ids'],
243 'courier_id' => $this->sanitize_value($data['courier_id']),
244 ), 'POST');
245 }
246
247 /**
248 *
249 * Sanitize shipstation tracking numbers. Moved to here from the
250 * class-routeapp-shipstation.php script because it is sometimes
251 * getting bypassed and orders are coming through with "-(SHIPSTATION)"
252 * at the end. Also added a more specific check for both a shipstation
253 * prefix and suffix WITH the dash since shipstation has moved the
254 * shipstation label to the back AND orders were coming through with
255 * either a leading or trailing "-"
256 *
257 * @param $value
258 * @return array|string
259 */
260
261 private function sanitize_value($value) {
262 $value = str_replace(['-(SHIPSTATION)', '(SHIPSTATION)-', '(Shipstation)'], '', $value);
263 $value = str_replace('.', '', $value);
264 $value = trim($value);
265 return $value;
266 }
267
268 /**
269 * Get the order shipment
270 * @param integer $tracking_id
271 * @param integer $order_id
272 * @param array $data
273 * @return mixed|json string
274 */
275 public function get_shipment($tracking_id, $order_id)
276 {
277 if (empty($tracking_id) || empty($order_id)) return false;
278 return $this->_make_private_api_call('shipments/' . $tracking_id . '?source_order_id=' . $order_id);
279 }
280
281 /**
282 * Update the order shipment, currently only status update suported by API
283 * @param integer $tracking_id
284 * @param integer $order_id
285 * @param array $data
286 * @return mixed|json string
287 */
288 public function update_shipment($tracking_id, $order_id, $data = array())
289 {
290 if (empty($tracking_id) || empty($order_id)) return false;
291 return $this->_make_private_api_call('shipments/' . $tracking_id . '?source_order_id=' . $order_id, array(
292 'source_order_id' => $data['source_order_id'],
293 'source_product_ids' => $data['source_product_ids'],
294 'courier_id' => $data['courier_id'],
295 ), 'POST');
296 }
297
298 /**
299 * Cancel the order shipment, currently only status update suported by API
300 * @param integer $tracking_id
301 * @param integer $order_id
302 * @param array $data
303 * @return mixed|json string
304 */
305 public function cancel_shipment($tracking_id, $data = array())
306 {
307 if (empty($tracking_id)) return false;
308 return $this->_make_private_api_call('shipments/' . $tracking_id . '/cancel' . '?source_order_id=' . $data['source_order_id'], array(
309 'source_order_id' => $data['source_order_id'],
310 'source_product_ids' => $data['source_product_ids'],
311 ), 'POST');
312 }
313
314 /**
315 * Create the order, currently only status update suported by API
316 * @param integer $data
317 * @return mixed|json string
318 */
319 public function create_order($data)
320 {
321 return $this->_make_private_api_call('orders', $data, 'POST', 'v2');
322 }
323
324 /**
325 * Get the order
326 * @param integer $source_order_id
327 * @return mixed|json string
328 */
329 public function get_order($source_order_id)
330 {
331 return $this->_make_private_api_call('orders/' . $source_order_id, 'GET');
332 }
333
334 /**
335 * Update the order, currently only status update suported by API
336 * @param integer $data
337 * @return mixed|json string
338 */
339 public function update_order($order_id, $data)
340 {
341 return $this->_make_private_api_call('orders/' . $order_id, $data, 'POST', 'v2');
342 }
343
344 /**
345 * Cancel the order, currently only status update suported by API
346 * @param integer $order_id
347 * @return mixed|json string
348 */
349 public function cancel_order($order_id)
350 {
351 return $this->_make_private_api_call('orders/' . $order_id . '/cancel', array(), 'POST');
352 }
353
354 /**
355 * Get user billing status settings
356 * @param integer $order_id
357 * @return mixed|json string
358 */
359 public function get_billing()
360 {
361 return $this->_make_private_api_call('billing', array(), 'GET');
362 }
363
364 /**
365 * Get the Route Merchant ID
366
367 * @return mixed
368 */
369 public function get_merchant_id()
370 {
371 return get_option(self::ROUTEAPP_MERCHANT_ID);
372 }
373
374 /**
375 * Get the Route Merchant ID
376 *
377 * @param $merchant_id
378 * @param $blog_id
379 *
380 * @return mixed
381 */
382 public function set_merchant_id($merchant_id, $blog_id = null){
383 if (isset($blog_id) && is_multisite()) {
384 return update_blog_option($blog_id, self::ROUTEAPP_MERCHANT_ID, $merchant_id);
385 }
386 return update_option(self::ROUTEAPP_MERCHANT_ID , $merchant_id);
387 }
388
389 public static function get_route_public_instance(){
390 global $routeapp_public;
391 return $routeapp_public;
392 }
393
394 /**
395 * Get merchant
396
397 * @return mixed
398 */
399 public function get_merchant()
400 {
401 if (!empty($this->_merchant)) {
402 return $this->_merchant;
403 }
404
405 $endpoint = 'merchants';
406 $merchantResponse = $this->get_merchant_id() ?
407 $this->_make_private_api_call($endpoint . '/' . $this->get_merchant_id(), array(), 'GET') :
408 $this->_make_private_api_call($endpoint, array(), 'GET');
409
410 try {
411 $response_code = wp_remote_retrieve_response_code($merchantResponse);
412
413 if ( is_wp_error($merchantResponse) || $response_code != 200 ) {
414 if ($response_code !== 403) {
415 $errorMsg = is_wp_error($merchantResponse) ? $merchantResponse->get_error_message() : $response_code;
416 throw new Exception("Route API Error while getting merchant data: " . $errorMsg);
417 }
418
419 $merchantResponse = $this->_make_private_api_call($endpoint, array(), 'GET');
420 }
421 } catch(Exception $exception) {
422 $routeapp_public = self::get_route_public_instance();
423 $routeapp_public->routeapp_log($exception, $this->_extraData);
424 return false;
425 }
426
427 if ($merchantResponse) {
428 if ($merchantResponse["body"]) {
429 $body = json_decode($merchantResponse["body"]);
430 $merchant = is_array($body) ? $body[0] : $body;
431
432 if ($merchant) {
433 $this->_merchant = $merchant;
434
435 if (empty($this->get_merchant_id()) || (isset($merchant->id) && $merchant->id !== $this->get_merchant_id())) {
436 $this->set_merchant_id($merchant->id, get_current_blog_id());
437 }
438 return $this->_merchant;
439 }
440 }
441
442 }
443 }
444
445 /**
446 * Create user account
447 * @param array $data
448 * @return mixed|json string
449 */
450 public function create_user($data) {
451 return $this->_make_private_api_call( 'users', $data, 'POST' );
452 }
453
454 /**
455 * Create user account
456 * @param $username
457 * @param $password
458 * @return mixed|json string
459 */
460 public function login_user($username, $password) {
461 return $this->_make_private_api_call( 'login', [
462 "username" => $username,
463 "password" => $password
464 ], 'POST' );
465 }
466
467 /**
468 * Create merchant account
469 * @param array $data
470 * @return mixed|json string
471 */
472 public function create_merchant($data) {
473 return $this->_make_private_api_call_using_user_token( 'merchants', $data, 'POST' );
474 }
475
476 /**
477 * Get merchant account by user
478 * @return mixed|json string
479 */
480 public function get_merchants() {
481 return $this->_make_private_api_call_using_user_token( "users/" . $this->get_user_id() . "/merchants", [], 'GET' );
482 }
483
484 /**
485 * Get activate account link at Route API
486 *
487 * @param array $email
488 * @return mixed|json string
489 */
490 public function activate_account($email) {
491 return $this->_make_private_api_call( 'activate_account', $email, 'POST' );
492 }
493
494 /**
495 * Get asset settings
496 * @param $apiHost
497 * @return mixed|json string
498 */
499 public function asset_settings($apiHost) {
500 return $this->_make_public_api_call("asset-settings/$apiHost", array(), 'GET');
501 }
502
503 /**
504 * Update the account status at Route API
505 *
506 * @return mixed|json string
507 */
508 public function update_merchant_status($status) {
509 $endpoint = 'merchants/' . $this->get_merchant_id();
510 $params = ['status' => $status];
511 return $this->_make_private_api_call( $endpoint, $params, 'POST' );
512 }
513
514 /*
515 * Make the call to the API
516 * @param string $endpoint
517 * @param array $params
518 * @param string $method
519 * @param string $version
520 * @return mixed|json string
521 */
522 private function _make_api_call($token, $endpoint, $params = array(), $method = 'GET', $version='v1')
523 {
524 $url = $version=='v1' ? $this->_api_url : $this->_api_url_v2;
525 $url.= $endpoint;
526
527 $extraData = array(
528 'params' => $params,
529 'method' => $method,
530 'endpoint' => $url
531 );
532 $this->_extraData = $extraData;
533
534 $headers = [
535 'Content-Type' => 'application/json',
536 'token' => $token,
537 ];
538 if ($version=='v2') {
539 $headers['Protect-Widget-Version'] = 'route-widget-core';
540 }
541 //platform
542 $headers['platform'] = 'woocommerce';
543
544 //woocommerce + wordpress version
545 $wooVersion = '';
546 if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) &&
547 defined('WC_VERSION') ) {
548 $wooVersion = WC_VERSION;
549 }
550 $wordpressVersion = '';
551 if (function_exists('get_bloginfo')) {
552 $wordpressVersion = get_bloginfo('version');
553 }
554 $headers['platform_version'] = 'WooCommerce: ' . $wooVersion . ' WordPress: ' . $wordpressVersion;
555
556 //route module version
557 $module_version= defined('ROUTEAPP_VERSION') ? ROUTEAPP_VERSION :'';
558 $headers['module_version'] = $module_version;
559
560 $args = array(
561 'timeout' => 6,
562 'method' => $method,
563 'headers' => $headers,
564 'body' => $method === 'POST' ? json_encode($params) : null
565 );
566
567 return wp_remote_request($url, $args);
568 }
569
570 private function _make_public_api_call($endpoint, $params = array(), $method = 'GET', $version='v1')
571 {
572 return $this->_make_api_call($this->get_public_token(), $endpoint, $params, $method, $version);
573 }
574
575 protected function _make_private_api_call($endpoint, $params = array(), $method = 'GET', $version='v1')
576 {
577 return $this->_make_api_call($this->get_secret_token(), $endpoint, $params, $method, $version);
578 }
579
580 protected function _make_private_api_call_using_user_token($endpoint, $params = array(), $method = 'GET', $version='v1')
581 {
582 return $this->_make_api_call($this->get_user_token(), $endpoint, $params, $method, $version);
583 }
584 }
585