From a239ef33ec489ce6d0f25ac2f256df0ac54a7e50 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 16 Sep 2026 00:07:34 +0000
Subject: [PATCH] =Tackling the integrations again. This time Helcim, with some minnor edits to GMB and Square
---
inc/integrations/services/Square.php | 27 ++++--
inc/integrations/services/GoogleMyBusiness.php | 69 +++++++++++++++++
inc/integrations/services/Helcim.php | 130 ++++++++++++++++++++++++++++++++
3 files changed, 215 insertions(+), 11 deletions(-)
diff --git a/inc/integrations/services/GoogleMyBusiness.php b/inc/integrations/services/GoogleMyBusiness.php
index 17d7df1..694285e 100644
--- a/inc/integrations/services/GoogleMyBusiness.php
+++ b/inc/integrations/services/GoogleMyBusiness.php
@@ -169,12 +169,81 @@
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;
diff --git a/inc/integrations/services/Helcim.php b/inc/integrations/services/Helcim.php
index d057b17..f388c96 100644
--- a/inc/integrations/services/Helcim.php
+++ b/inc/integrations/services/Helcim.php
@@ -4,6 +4,12 @@
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;
@@ -22,10 +28,132 @@
*/
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;
+ }
}
diff --git a/inc/integrations/services/Square.php b/inc/integrations/services/Square.php
index 89d49c1..c642247 100644
--- a/inc/integrations/services/Square.php
+++ b/inc/integrations/services/Square.php
@@ -254,10 +254,15 @@
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(),
@@ -279,16 +284,18 @@
}
$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
--
Gitblit v1.10.0