/
var
/
www
/
html
/
sugar13
/
modules
/
SF_Subscriptions
/
Upload File
HOME
<?php /* * SubscriptionFlow Package for SugarCRM * * Copyright (C) SubscriptionFlow. All rights reserved. * * Your installation or use of this package is subject to the applicable * terms available at https://www.subscriptionflow.com/terms-and-conditions * If you do not agree to all of the applicable terms, do not install or use this package. * Support: https://support.subscriptionflow.com */ use Sugarcrm\Sugarcrm\Security\HttpClient\ExternalResourceClient; use Sugarcrm\Sugarcrm\Security\HttpClient\RequestException; use Sugarcrm\Sugarcrm\Util\Uuid; class SF_SubscriptionFlow_Sync { public $token_endpoint = "/oauth/token"; public $grant_type = "client_credentials"; public $content_type = "application/json"; public $base_url = ""; public $status = false; public $domain = ""; public $client_id = ""; public $client_secret = ""; public $access_token = null; public $token_type = null; public $expires_in = null; public $created_at = null; public $updated_at = null; public $error = null; private $original_response = null; private $logger = null; public function __construct() { $this->logger = $GLOBALS['log']; } public function setCredentials($domain, $client_id, $client_secret) { $this->domain = trim($domain); $this->client_id = trim($client_id); $this->client_secret = trim($client_secret); $this->base_url = "https://" . $this->domain . ".subscriptionflow.com"; } public function createCustomer($payload) { $customer = null; $customerResponse = $this->makeRequest("/api/v1/customers", "POST", [], json_encode($payload)); if (isset($customerResponse['data']) && isset($customerResponse['data']['attributes'])) { $customer = $customerResponse['data']['attributes']; } return $customer; } public function createSubscription($payload) { $subscription = null; $subscriptionResponse = $this->makeRequest("/api/v1/subscriptions", "POST", [], json_encode($payload)); if (isset($subscriptionResponse['data']) && isset($subscriptionResponse['data']['attributes'])) { $subscription = $subscriptionResponse['data']['attributes']; } return $subscription; } public function getInvoice($id) { $invoice = null; $invoiceResponse = $this->makeRequest("/api/v1/invoices/$id", "GET"); if (isset($invoiceResponse['data']) && isset($invoiceResponse['data']['attributes'])) { $invoice = $invoiceResponse['data']['attributes']; } return $invoice; } public function getSubscriptions($filters = []) { $subscriptions = []; $subscriptionsResponse = $this->makeRequest("/api/v1/subscriptions/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $filters); if (is_array($subscriptionsResponse["data"]) && count($subscriptionsResponse["data"]) > 0) { foreach ($subscriptionsResponse["data"] as $subscription) { $subscriptions[] = $subscription; } } return $subscriptions; } public function getInvoices($filters = []) { $invoices = []; $invoicesResponse = $this->makeRequest("/api/v1/invoices/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $filters); if (is_array($invoicesResponse["data"]) && count($invoicesResponse["data"]) > 0) { foreach ($invoicesResponse["data"] as $invoice) { $invoices[] = $invoice; } } return $invoices; } public function syncPlanPrices($plan_id, $product_id, $currency = null, $idInKey = false) { $planPrices = []; $planPricesResponse = $this->makeRequest("/api/v1/plans/" . $plan_id . "/link/plan_price", "GET"); if (is_array($planPricesResponse["data"]) && count($planPricesResponse["data"]) > 0) { foreach ($planPricesResponse["data"] as $price) { $charge_price = 0; if (isset($price["list_price"]) && is_array($price["list_price"])) { if (isset($price["list_price"][$currency])) { $charge_price = $price["list_price"][$currency]; } else { $charge_price = array_values($price["list_price"])[0]; } } else { $charge_price = $price["list_price"]; } $price["list_price_string"] = $charge_price; if (isset($price['category']) && $price['category'] == 'recurring') { $price["renewable"] = 1; } else { $price["renewable"] = 0; } $this->update_billing_period_id($price); if ($idInKey) { $planPrices[$price["id"]] = $price; } else { $planPrices[] = $price; } } } return $planPrices; } public function syncProducts($filters = []) { $products = []; $data = array('filter[$select]' => "id, name", 'filter[$paginate]' => 50); foreach ($filters as $key => $value) { $data['filter[' . $key . '][$contains]'] = $value; } $productsResponse = $this->makeRequest("/api/v1/products/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $data); if (is_array($productsResponse["data"]) && count($productsResponse["data"]) > 0) { foreach ($productsResponse["data"] as $product) { $item["id"] = $product["id"]; $item["text"] = $product["name"]; $products[] = $item; } } return $products; } public function syncCustomers($filters = []) { $customers = []; $customersResponse = $this->makeRequest("/api/v1/customers/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $filters); if (is_array($customersResponse["data"]) && count($customersResponse["data"]) > 0) { foreach ($customersResponse["data"] as $customer) { $item["id"] = $customer["id"]; $item["text"] = $customer["name"]; $customers[] = $item; } } return $customers; } private function update_billing_period_id(&$price) { $value = null; $duration = null; switch ($price['billing_period_id']) { case 1: $value = 'Month'; $duration = 1; break; case 2: $value = 'Months'; $duration = 3; break; case 3: $value = 'Months'; $duration = 6; break; case 4: $value = 'Year'; $duration = 1; break; case 5: $value = 'Week'; $duration = 1; break; case 6: $value = 'Years'; $duration = 2; break; case 7: $value = 'Months'; $duration = 18; break; case 8: $value = 'Years'; $duration = 3; break; case 9: $value = 'Years'; $duration = 5; break; case 10: $value = 'Subscription'; $duration = 1; break; case 11: $value = 'Weeks'; $duration = 0; break; case 12: $value = 'Months'; $duration = 0; break; default: $value = null; $duration = null; break; } $price['service_durations'] = $duration; $price['service_duration_units'] = $value; } public function syncPlans($filters = [], $product = null) { $plans = []; if ($product) { $plansResponse = $this->makeRequest("/api/v1/products/" . $product . "/link/plans", "GET"); if (is_array($plansResponse["data"]) && count($plansResponse["data"]) > 0) { foreach ($plansResponse["data"] as $plan) { $item["id"] = $plan["id"]; $item["text"] = $plan["name"]; $plans[] = $item; } } } else { $data = array('filter[$select]' => "id, name", 'filter[$paginate]' => 50); foreach ($filters as $key => $value) { $data['filter[' . $key . '][$contains]'] = $value; } $plansResponse = $this->makeRequest("/api/v1/plans/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $data); if (is_array($plansResponse["data"]) && count($plansResponse["data"]) > 0) { foreach ($plansResponse["data"] as $plan) { $item["id"] = $plan["id"]; $item["text"] = $plan["name"]; $plans[] = $item; } } } return $plans; } public function getProductDetail($id) { $product = null; $productResponse = $this->makeRequest("/api/v1/products/$id", "GET"); if (isset($productResponse['data']) && isset($productResponse['data']['attributes'])) { $product = $productResponse['data']['attributes']; } return $product; } public function getPlanDetail($id) { $plan = null; $planResponse = $this->makeRequest("/api/v1/plans/$id", "GET"); if (isset($planResponse['data']) && isset($planResponse['data']['attributes'])) { $plan = $planResponse['data']['attributes']; } return $plan; } public function syncPlansProducts($filters = []) { $product_plans = []; $products = []; $plans = []; $data = array('filter[$select]' => "id, name", 'filter[$paginate]' => 10);//, 'filter[$sortorder]' => 'DESC' foreach ($filters as $key => $value) { $data['filter[' . $key . '][$contains]'] = $value; } $plansResponse = $this->makeRequest("/api/v1/plans/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $data); if (is_array($plansResponse["data"]) && count($plansResponse["data"]) > 0) { foreach ($plansResponse["data"] as $plan) { $plans[$plan["id"]] = $plan["name"]; $productsResponse = $this->makeRequest("/api/v1/plans/" . $plan["id"] . "/link/products", "GET"); if (is_array($productsResponse["data"]) && count($productsResponse["data"]) > 0) { foreach ($productsResponse["data"] as $product) { $products[$product["id"]] = $product["name"]; $product_plans[$plan["id"]][$product["id"]]["product_id"] = $product["id"]; $product_plans[$plan["id"]][$product["id"]]["product_name"] = $product["name"]; $product_plans[$plan["id"]][$product["id"]]["plan_id"] = $plan["id"]; $product_plans[$plan["id"]][$product["id"]]["plan_name"] = $plan["name"]; } } } } return $plans; } public function syncPlans2($filters = []) { $product_plans = []; $products = []; $plans = []; $prices = []; $data = array('filter[$select]' => "id, name", 'filter[$paginate]' => 10); $productsResponse = $this->makeRequest("/api/v1/products/filter", "POST", ["Content-Type" => "application/x-www-form-urlencoded"], $data); if (is_array($productsResponse["data"]) && count($productsResponse["data"]) > 0) { foreach ($productsResponse["data"] as $product) { $products[$product["id"]] = $product["name"]; $plansResponse = $this->makeRequest("/api/v1/products/" . $product["id"] . "/link/plans", "GET"); if (is_array($plansResponse["data"]) && count($plansResponse["data"]) > 0) { foreach ($plansResponse["data"] as $plan) { $plan[$plan["id"]] = $plan["name"]; /*$planPricesResponse = $this->makeRequest("/api/v1/plans/" . $plan["id"] . "/link/plan_price", "GET"); if (is_array($planPricesResponse["data"]) && count($planPricesResponse["data"]) > 0) { foreach ($planPricesResponse["data"] as $plan_price) { $product_plans[$product["id"]][$plan["id"]][$plan_price["id"]]["plan_price_id"] = $plan_price["id"]; $product_plans[$product["id"]][$plan["id"]][$plan_price["id"]]["plan_price_name"] = $plan_price["name"]; } }*/ $product_plans[$product["id"]][$plan["id"]]["product_id"] = $product["id"]; $product_plans[$product["id"]][$plan["id"]]["product_name"] = $product["name"]; $product_plans[$product["id"]][$plan["id"]]["plan_id"] = $plan["id"]; $product_plans[$product["id"]][$plan["id"]]["plan_name"] = $plan["name"]; } } } } return $plans; } public function testConnection() { return $this->generateAccessToken(); } private function generateAccessToken() { $status = false; try { $endpoint = $this->token_endpoint; $response = $this->makeRequest($endpoint, "POST", [], json_encode(['client_id' => trim($this->client_id), 'client_secret' => trim($this->client_secret), 'grant_type' => trim($this->grant_type)])); if (!empty($response["access_token"])) { $this->access_token = $response["access_token"]; $this->token_type = $response["token_type"]; $this->expires_in = $response["expires_in"]; $status = true; $this->logger->debug("Successfully received an access token from SubscriptionFlow. Access Token expires in: " . $this->expires_in); } else { $this->error = "Invalid Response from SubscriptionFlow"; $this->logger->fatal("Invalid Response received from SubscriptionFlow [$endpoint]"); $this->logger->fatal("Reason Phrase: " . $this->original_response->getReasonPhrase()); $this->logger->fatal("Status Code: " . $this->original_response->getStatusCode()); $this->logger->fatal("Response Body: "); $this->logger->fatal(print_r($response, true)); } } catch (RequestException $e) { $this->logException($e, $this->token_endpoint); } return $status; } private function isTokenExpired() { $status = false; if ($this->access_token && $this->expires_in && $this->updated_at) { $now = time(); $expires_at = $this->updated_at + $this->expires_in; if ($now >= $expires_at) { $status = true; } } return $status; } public function loadConnection() { $this->logger->debug("Loading SubscriptionFlow Connection Information"); require_once("modules/Administration/Administration.php"); $administration = Administration::getSettings('SF_Subscriptions'); $connectionData = []; if (isset($administration->settings) && isset($administration->settings['SF_Subscriptions_Connection'])) { $serializedData = $administration->settings['SF_Subscriptions_Connection']; if ($serializedData) { $serializedData = trim($serializedData); $serializedData = base64_decode($serializedData); $existingData = unserialize($serializedData); if (is_array($existingData) && count($existingData) > 0) { $connectionData = $existingData; } } } $this->status = $connectionData["status"] ?? false; $this->domain = $connectionData["domain"] ?? ""; $this->client_id = $connectionData["client_id"] ?? ""; $this->client_secret = $connectionData["client_secret"] ?? ""; $this->access_token = $connectionData["access_token"] ?? null; $this->token_type = $connectionData["token_type"] ?? null; $this->expires_in = $connectionData["expires_in"] ?? null; $this->created_at = $connectionData["created_at"] ?? null; $this->updated_at = $connectionData["updated_at"] ?? null; if ($this->isTokenExpired()) { $this->logger->fatal("Access Token expired. Generated a new access token"); $this->generateAccessToken(); $this->saveConnection(true); } $this->logger->debug("Successfully loaded SubscriptionFlow Connection Information"); $this->base_url = "https://" . $this->domain . ".subscriptionflow.com"; } public function saveConnection($is_update = false) { $this->logger->debug("Saving SubscriptionFlow Connection Information"); require_once("modules/Administration/Administration.php"); $administration = Administration::getSettings('SF_Subscriptions'); $connectionData = []; if (isset($administration->settings) && isset($administration->settings['SF_Subscriptions_Connection'])) { $serializedData = $administration->settings['SF_Subscriptions_Connection']; if ($serializedData) { $serializedData = trim($serializedData); $serializedData = base64_decode($serializedData); $existingData = unserialize($serializedData); if (is_array($existingData) && count($existingData) > 0) { $connectionData = $existingData; } } } $administration = new Administration(); $connectionData["domain"] = $this->domain; $connectionData["client_id"] = $this->client_id; $connectionData["client_secret"] = $this->client_secret; $connectionData["access_token"] = $this->access_token; $connectionData["token_type"] = $this->token_type; $connectionData["expires_in"] = $this->expires_in; $connectionData["status"] = 1; $connectionData["deleted"] = 0; $connectionData["assigned_user_id"] = $GLOBALS['current_user']->id; $connectionData["modified_user_id"] = $GLOBALS['current_user']->id; $connectionData["modified_by"] = $GLOBALS['current_user']->id; $connectionData["updated_at"] = time(); if (!$is_update) { $connectionData["created_at"] = time(); $connectionData["id"] = uuid::uuid1(); $connectionData["created_by"] = $GLOBALS['current_user']->id; $connectionData["team_id"] = $GLOBALS['current_user']->default_team; $connectionData["team_set_id"] = $GLOBALS['current_user']->default_team; } $serializedData = base64_encode(serialize($connectionData)); $administration->saveSetting("SF_Subscriptions", "Connection", $serializedData); $this->logger->debug("Successfully saved SubscriptionFlow Connection Information"); } public function revokeConnection() { $this->logger->debug("Revoking SubscriptionFlow access"); require_once("modules/Administration/Administration.php"); $administration = new Administration(); $connectionData["revoked_by"] = $GLOBALS['current_user']->id; $connectionData["revoked_at"] = time(); $serializedData = base64_encode(serialize($connectionData)); $administration->saveSetting("SF_Subscriptions", "Connection", $serializedData); $this->logger->debug("SubscriptionFlow access revoked by " . "[" . $GLOBALS['current_user']->id . "] " . $GLOBALS['current_user']->name); } private function logException($e, $endpoint) { $this->error = $e->getMessage(); $this->logger->fatal("An exception occurred while testing connection with SubscriptionFlow [$endpoint]"); $this->logger->fatal("Code: " . $e->getCode()); $this->logger->fatal("Message: " . $e->getMessage()); $this->logger->fatal("File: " . $e->getFile()); $this->logger->fatal("Line: " . $e->getLine()); $this->logger->fatal($e->getTraceAsString()); } private function makeRequest($endpoint, $type = "POST", $headers = [], $data = []) { $response = null; $this->original_response = null; try { $url = $this->base_url . $endpoint; $this->logger->debug("Making a request to SubscriptionFlow [$url]"); $headers["Content-type"] = $this->content_type; if ($endpoint != $this->token_endpoint) { $headers["Authorization"] = "Bearer $this->access_token"; } $externalResourceClient = new ExternalResourceClient(); if ($type == "GET") { $this->original_response = $externalResourceClient->get($url, $headers); } else if ($type == "POST") { $this->original_response = $externalResourceClient->post($url, $data, $headers); } else if ($type == "PUT") { } if ($this->original_response && $this->original_response->getBody()) { $response = json_decode($this->original_response->getBody(), true); } else { $this->error = "Invalid Response from SubscriptionFlow"; $this->logger->fatal("Invalid Response received from SubscriptionFlow [$endpoint]"); $this->logger->fatal("Reason Phrase: " . $this->original_response->getReasonPhrase()); $this->logger->fatal("Status Code: " . $this->original_response->getStatusCode()); $this->logger->fatal("Response: "); $this->logger->fatal(print_r($this->original_response, true)); } } catch (RequestException $e) { $this->logException($e, $endpoint); } return $response; } }