=Tackling the integrations again. This time Helcim, with some minnor edits to GMB and Square
| | |
| | | |
| | | protected function refreshAccessToken(OAuthCredentials $credentials): array |
| | | { |
| | | if (empty($this->getClientID()) || empty($this->getClientSecret()) || empty($credentials->refresh_token)) { |
| | | $this->logError('refreshAccessToken', 'Missing refresh token'); |
| | | return $this->response(false, 'Missing client ID, client Secret, or refresh token'); |
| | | } |
| | | $response = wp_remote_post( |
| | | $this->oauth->getToken(), |
| | | [ |
| | | 'timeout' => 15, |
| | | 'body' => [ |
| | | 'grant_type' => 'refresh_token', |
| | | 'refresh_token' => $credentials->refresh_token, |
| | | 'client_id' =>$this->getClientID(), |
| | | 'client_secret' =>$this->getClientSecret() |
| | | ], |
| | | 'headers' => $this->getOAuthRequestHeaders() |
| | | ] |
| | | ); |
| | | if (is_wp_error($response)) { |
| | | $this->logError( |
| | | 'refreshAccessToken', |
| | | 'Failed to refresh GMB Token', |
| | | [ |
| | | 'error' => $response->get_error_message() |
| | | ] |
| | | ); |
| | | return $this->response(false, 'Failed to refresh GMB Token'); |
| | | } |
| | | |
| | | $data = json_decode(wp_remote_retrieve_body($response), true); |
| | | if (empty($data['access_token'])) { |
| | | $this->logError('refreshAccessToken', 'No access token in response'); |
| | | return $this->response(false, 'No access token in response'); |
| | | } |
| | | $credentials = [ |
| | | 'access_token' => $data['access_token'], |
| | | 'expires_at' => time() + (int)($data['expires_in']??3600), |
| | | // Google usually omits refresh_token on refresh — keep the old one |
| | | 'refresh_token' => $body['refresh_token'] ?? $credentials->refresh_token, |
| | | ]; |
| | | $this->saveCredentials($credentials); |
| | | |
| | | return $this->response(true, 'Successfully refreshed token'); |
| | | } |
| | | |
| | | /********************************************************* |
| | | * UTILITY |
| | | *********************************************************/ |
| | | protected function getClientID():string|false |
| | | { |
| | | $switch = false; |
| | | if ($this->userID !== null) { |
| | | $switch = $this->userID; |
| | | $this->switchUser(null); |
| | | } |
| | | |
| | | $ID = $this->loadCredentials()['client_id']??false; |
| | | if ($switch) { |
| | | $this->switchUser($switch); |
| | | } |
| | | return $ID; |
| | | } |
| | | protected function getClientSecret():string|false |
| | | { |
| | | $switch = false; |
| | | if ($this->userID !== null) { |
| | | $switch = $this->userID; |
| | | $this->switchUser(null); |
| | | } |
| | | |
| | | $ID = $this->loadCredentials()['client_secret']??false; |
| | | if ($switch) { |
| | | $this->switchUser($switch); |
| | | } |
| | | return $ID; |
| | | } |
| | | protected function getAccountID():string|false |
| | | { |
| | | return $this->loadCredentials()['account_id']??false; |
| | |
| | | use JVBase\integrations\Admin; |
| | | use JVBase\Instance; |
| | | use JVBase\integrations\Integrations; |
| | | use JVBase\integrations\OAuth; |
| | | use JVBase\integrations\OAuthCredentials; |
| | | use JVBase\integrations\Requests; |
| | | use JVBase\integrations\SyncToPost; |
| | | use JVBase\integrations\UserConnection; |
| | | use WP_Error; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; |
| | |
| | | */ |
| | | class Helcim extends Integrations |
| | | { |
| | | use Admin, Instance; |
| | | use Admin, Instance, OAuth, Requests, UserConnection, SyncToPost; |
| | | |
| | | protected function __construct() |
| | | { |
| | | $this->service_name = 'helcim'; |
| | | $this->title = 'Helcim'; |
| | | $this->icon = 'currency-dollar'; |
| | | |
| | | $this->canSync = [ |
| | | 'initial' => true, |
| | | 'update' => true, |
| | | 'delete' => true, |
| | | ]; |
| | | |
| | | $this->baseUrl = 'https://api.helcim.com/v2'; |
| | | |
| | | $this->defineFields(); |
| | | $this->defineInstructions(); |
| | | $this->defineActions(); |
| | | |
| | | parent::__construct(); |
| | | } |
| | | protected function defineFields():void |
| | | { |
| | | $api_token = $this->addField( |
| | | 'api_token', |
| | | 'API Token', |
| | | 'text', |
| | | [$this, 'testUserCanConnect'] |
| | | ); |
| | | $api_token->setSubType('password'); |
| | | $api_token->setRequired(); |
| | | $api_token->setHint('Found in Helcim Dashboard → Settings → API Access'); |
| | | |
| | | $currency = $this->addField( |
| | | 'currency', |
| | | 'Currency', |
| | | 'select', |
| | | [$this, 'testUserSetup'] |
| | | ); |
| | | $currency->setOptions([ |
| | | 'CAD' => 'CAD', |
| | | 'USD' => 'USD' |
| | | ]); |
| | | $currency->setDefault('CAD'); |
| | | |
| | | $feeSaver = $this->addField( |
| | | 'fee_saver', |
| | | 'Fee Saver', |
| | | 'true_false', |
| | | [$this, 'testUserSetup'] |
| | | ); |
| | | $feeSaver->setHint('Pass processing fees to customers? (Not compatible with Google Pay)'); |
| | | |
| | | $allowACH = $this->addField( |
| | | 'allow_ach', |
| | | 'Allow ACH/Bank Payments', |
| | | 'true_false', |
| | | [$this, 'testUserSetup'] |
| | | ); |
| | | $allowACH->setHint('Enable bank account payments alongside credit card'); |
| | | } |
| | | public function testUserCanConnect():bool |
| | | { |
| | | $user = get_current_user_id(); |
| | | return $this->userCanConnect($user); |
| | | } |
| | | public function testUserSetup():bool |
| | | { |
| | | return $this->isSetUp() && $this->testUserCanConnect() && !empty($this->getApiToken()); |
| | | } |
| | | |
| | | protected function defineInstructions():void |
| | | { |
| | | $this->instructions = [ |
| | | 'Go to <a href="https://my.helcim.com" target="_blank">Helcim Dashboard</a>', |
| | | 'Navigate to Settings → API Access', |
| | | 'Create a new API Access Configuration', |
| | | 'Enable permissions: General (Customers, Invoices, Products), Transaction Processing', |
| | | 'Copy the API Token and paste it below', |
| | | ]; |
| | | } |
| | | |
| | | protected function defineActions():void |
| | | { |
| | | $this->addAction( |
| | | 'Initialize Checkout', |
| | | [$this, 'initializeCheckout'], |
| | | 'initialize_checkout' |
| | | ); |
| | | } |
| | | |
| | | protected function initialize(): void |
| | | { |
| | | // TODO: Implement initialize() method. |
| | | } |
| | | |
| | | protected function refreshAccessToken(OAuthCredentials $credentials): array |
| | | { |
| | | // TODO: Implement refreshAccessToken() method. |
| | | } |
| | | |
| | | protected function getRequestHeaders(): array |
| | | { |
| | | // TODO: Implement getRequestHeaders() method. |
| | | } |
| | | |
| | | protected function handleResponse(WP_Error|array $response, string $method, string $endpoint): array |
| | | { |
| | | // TODO: Implement handleResponse() method. |
| | | } |
| | | |
| | | protected function setContentTypes(): void |
| | | { |
| | | // TODO: Implement setContentTypes() method. |
| | | } |
| | | |
| | | protected function formatForService(int $itemID, string $type = 'post'): array |
| | | { |
| | | // TODO: Implement formatForService() method. |
| | | } |
| | | /************************************************************************* |
| | | * UTILITY |
| | | *************************************************************************/ |
| | | protected function getApiToken():string|false |
| | | { |
| | | return $this->loadCredentials()['api_token']??false; |
| | | } |
| | | } |
| | |
| | | |
| | | protected function refreshAccessToken(OAuthCredentials $credentials): array |
| | | { |
| | | if (!$this->getClientID() || !$this->getClientSecret()) |
| | | if (!$this->getClientID() || !$this->getClientSecret() || empty($credentials->refresh_token)) { |
| | | $this->logError('refreshAccessToken', 'Missing client credentials or refresh token'); |
| | | return $this->response(false, 'No client ID or client secret provided'); |
| | | } |
| | | |
| | | $response = wp_remote_post( |
| | | $this->oauth->getToken(), |
| | | [ |
| | | 'timeout' => 15, |
| | | 'body' => [ |
| | | 'client_id' => $this->getClientID(), |
| | | 'client_secret' => $this->getClientSecret(), |
| | |
| | | } |
| | | |
| | | $data = json_decode(wp_remote_retrieve_body($response)); |
| | | if (isset($data['access_token'])) { |
| | | $credentials = [ |
| | | 'access_token' => $data['access_token'], |
| | | 'expires_at' => time() + ($data['expires_in'] ?? 2592000) // 30 days default |
| | | ]; |
| | | |
| | | $this->saveCredentials($credentials); |
| | | return $this->response(true, 'Successfully refreshed access token'); |
| | | if (empty($data['access_token'])) { |
| | | $this->logError('refreshAccessToken', 'No access_token in refresh response', ['body' => $data]); |
| | | return $this->response(false, 'No Access Token in Response'); |
| | | } |
| | | return $this->response(false, 'Something went wrong that wasn\'t caught - could not refresh access token'); |
| | | $credentials = [ |
| | | 'access_token' => $data['access_token'], |
| | | 'expires_at' => strtotime($data['expires_at'] ?? '') ?: (time() + 2592000), |
| | | 'refresh_token' => $data['refresh_token'] ?? $credentials->refresh_token, |
| | | ]; |
| | | $this->saveCredentials($credentials); |
| | | |
| | | return $this->response(true, 'Successfully refreshed access token'); |
| | | } |
| | | |
| | | protected function getRequestHeaders(): array |