| | |
| | | use Exception; |
| | | use JVBase\integrations\Admin; |
| | | use JVBase\integrations\APIEndpoint; |
| | | use JVBase\integrations\Instance; |
| | | use JVBase\Instance; |
| | | use JVBase\integrations\Integrations; |
| | | use JVBase\integrations\OAuth; |
| | | use JVBase\integrations\OAuthCredentials; |
| | |
| | | use JVBase\integrations\SyncFrom; |
| | | use JVBase\integrations\SyncTo; |
| | | use JVBase\integrations\Webhooks; |
| | | use JVBase\managers\Dashboard\Dashboard; |
| | | use JVBase\managers\queue\executors\IntegrationExecutor; |
| | | use JVBase\managers\queue\Queue; |
| | | use JVBase\managers\queue\TypeConfig; |
| | | use JVBase\meta\Sanitizer; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\ui\CRUDSkeleton; |
| | | use WP_Error; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | |
| | | Webhooks; |
| | | |
| | | protected string $orderPostType = '_square_order'; |
| | | protected string $apiVersion = '2026-07-15'; |
| | | public bool $hasBatchCreate = true; |
| | | public bool $hasBatchUpdate = true; |
| | | public bool $hasBatchDelete = true; |
| | | public array $apiEndpoints = [ |
| | | |
| | | ]; |
| | | |
| | | protected function __construct() |
| | | { |
| | | $this->service_name = 'square'; |
| | | $this->title = 'Square'; |
| | | $this->icon = 'square-logo'; |
| | | $this->apiVersion = '2026-07-15'; |
| | | $this->supportsWebp = false; |
| | | |
| | | $this->canSync = [ |
| | |
| | | 'update' => true, |
| | | 'delete' => true, |
| | | ]; |
| | | $this->hasBatchCreate = true; |
| | | $this->hasBatchUpdate = true; |
| | | $this->hasBatchDelete = true; |
| | | |
| | | $this->defineFields(); |
| | | $this->defineInstructions(); |
| | |
| | | $locs->setHidden(); |
| | | $locs->setOptions($this->getLocationOptions()); |
| | | |
| | | $loc = $this->addField('location_id', 'Default Location', 'select', 'manage_options'); |
| | | $loc->setOptions($this->loadCredentials()['locations']); |
| | | $loc = $this->addField('location_id', 'Set Location', 'select', 'manage_options'); |
| | | $loc->setOptions($this->loadCredentials()['locations']??[]); |
| | | $loc->setHint('Select default Square location for transactions'); |
| | | } |
| | | |
| | |
| | | add_action(BASE.'dashboard_page_orders', [$this, 'renderDashPage']); |
| | | } |
| | | |
| | | public function addDashboardPages():void |
| | | { |
| | | $page = Dashboard::getInstance()->addPage('Your Orders', 'orders', 'receipt'); |
| | | $page->setScripts(['jvb-crud']); |
| | | } |
| | | |
| | | public function renderDashPage():void |
| | | { |
| | | $this->determineUser(); |
| | | |
| | | $crud = new CRUDSkeleton(); |
| | | $crud->icon('receipt'); |
| | | $crud->title('Your Orders','Here you can see your past orders, and reorder from there if you\'d like'); |
| | | $crud->content($this->orderPostType, 'Order', 'Orders'); |
| | | $crud->addSearch(); |
| | | $crud->addCapabilities(['view']); |
| | | $crud->setEmptyState(sprintf( |
| | | '<div class="empty-state"> |
| | | <h3>%sNothing here%s</h3> |
| | | <p>It doesn\'t look like you have any orders yet.</p> |
| | | <p>Head on over to <a href="%s">our menu</a> and make your first order!</p> |
| | | </div>', |
| | | jvbDashIcon($crud->getIcon()), |
| | | jvbDashIcon($crud->getIcon()), |
| | | get_post_type_archive_link(BASE.'menu_item') |
| | | )); |
| | | |
| | | |
| | | $crud->render(); |
| | | } |
| | | |
| | | protected function initialize(): void |
| | | { |
| | | $this->defineEndpoints(); |
| | |
| | | |
| | | 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 |
| | |
| | | ]; |
| | | } |
| | | |
| | | protected function handleResponse(\WP_Error|array $response, string $method, string $endpoint): array |
| | | protected function handleResponse(WP_Error|array $response, string $method, string $endpoint): array |
| | | { |
| | | if (is_wp_error($response) && $response->get_error_message() === 'rate_limit_exceeded') { |
| | | return $this->response(false, 'Rate limit exceeded'); |
| | | } |
| | | $endpoint = str_replace($this->getBaseURL(), '', $endpoint); |
| | | switch ($endpoint) { |
| | | case '/v2/customers/search': |
| | | return $this->handleEmailSearchResponse($response, $method); |
| | | case '/v2/customers': |
| | | return $this->handleCreateUserResponse($response, $method); |
| | | case '/v2/locations': |
| | | return $this->handleGetLocationResponse($response, $method); |
| | | } |
| | | return $this->response(false, 'Unhandled Response for '.$endpoint.' endpoint, with method: '.$method); |
| | | return match ($endpoint) { |
| | | '/v2/customers/search' => $this->handleEmailSearchResponse($response, $method), |
| | | '/v2/customers' => $this->handleCreateUserResponse($response, $method), |
| | | '/v2/locations' => $this->handleGetLocationResponse($response, $method), |
| | | default => $this->response(false, 'Unhandled Response for ' . $endpoint . ' endpoint, with method: ' . $method), |
| | | }; |
| | | } |
| | | |
| | | protected function setContentTypes(): void |
| | |
| | | ********************************************************************/ |
| | | protected function registerAdditionalQueueTypes(IntegrationExecutor $executor): void |
| | | { |
| | | $queue = JVB()->queue(); |
| | | $queue = Queue::getInstance(); |
| | | $queue->registry()->register( |
| | | self::$syncCustomer, |
| | | new TypeConfig( |
| | |
| | | { |
| | | return $this->loadCredentials()['location_id']??false; |
| | | } |
| | | protected function getLocations():array|false |
| | | public function getLocations():array|false |
| | | { |
| | | if (!$this->getAccessToken()) { |
| | | return false; |
| | |
| | | ? 'https://connect.squareup.com' |
| | | : 'https://connect.squareupsandbox.com'; |
| | | } |
| | | protected function getAccessToken():string |
| | | { |
| | | return $this->loadCredentials()['access_token']??''; |
| | | } |
| | | |
| | | /*************************************************************** |
| | | * ACTIONS |
| | | ***************************************************************/ |
| | |
| | | return $this->contentTypes[$content_type]; |
| | | } |
| | | |
| | | public function handleImportFromSquare():array |
| | | { |
| | | |
| | | return $this->response(true, 'Did a thing'); |
| | | } |
| | | |
| | | public function handleSyncToSquare():array |
| | | { |
| | | |
| | | return $this->response(true, 'Did a thing'); |
| | | } |
| | | |
| | | |
| | | } |