From 0dfe1d8afafc59c4a5559c498342668d5a58d6ef Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 23 Jul 2026 22:41:41 +0000
Subject: [PATCH] =Still working away at the Integrations overhaul

---
 inc/integrations/services/Square.php |  359 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 352 insertions(+), 7 deletions(-)

diff --git a/inc/integrations/services/Square.php b/inc/integrations/services/Square.php
index e3dbfff..a2b6c9a 100644
--- a/inc/integrations/services/Square.php
+++ b/inc/integrations/services/Square.php
@@ -3,6 +3,7 @@
 namespace JVBase\integrations\services;
 use Exception;
 use JVBase\integrations\Admin;
+use JVBase\integrations\APIEndpoint;
 use JVBase\integrations\Instance;
 use JVBase\integrations\Integrations;
 use JVBase\integrations\OAuth;
@@ -35,7 +36,13 @@
 		Webhooks;
 
 	protected string $orderPostType = '_square_order';
-	protected string $apiVersion = '2025-09-24';
+	protected string $apiVersion = '2026-07-15';
+	public bool $hasBatchCreate = true;
+	public bool $hasBatchUpdate = true;
+	public bool $hasBatchDelete = true;
+	public array $apiEndpoints = [
+
+	];
 
 	protected function __construct()
 	{
@@ -157,8 +164,58 @@
 
 	protected function initialize(): void
 	{
-		// TODO: Implement initialize() method.
+		$this->defineEndpoints();
 	}
+		protected function defineEndpoints():void
+		{
+			$this->defineCustomerEndpoints();
+			$this->defineProductEndpoints();
+			$this->defineOrderEndpoints();
+			$this->definePaymentEndpoints();
+		}
+			protected function defineCustomerEndpoints():void
+			{
+				$customer = new APIEndpoint();
+				$customer->setCreate('/v2/customers');
+				$customer->setBatchCreate('/v2/customers/bulk-create');
+				$customer->setDelete('/v2/customers/');//add the item_id to the end
+				$customer->setBatchDelete('/v2/customers/bulk-delete');
+				$customer->setUpdate('/v2/customers/');//add the item_id to the end
+				$customer->setBatchUpdate('/v2/customers/bulk-update');
+				$customer->setSearch('/v2/customers/search');
+				$customer->setImport('/v2/customers');
+				$this->apiEndpoints['customer'] = $customer;
+			}
+			protected function defineProductEndpoints():void
+			{
+				$product = new APIEndpoint();
+				$product->setSearch('/v2/catalog/search-catalog-items');
+				$product->setImport('/v2/catalog/list');
+				$product->setImage('/v2/catalog/images');
+				$product->setCreate('/v2/catalog/object');
+				$product->setBatchCreate('/v2/catalog/batch-upsert');
+				$product->setUpdate('/v2/catalog/object');
+				$product->setBatchUpdate('/v2/catalog/batch-upsert');
+				$product->setDelete('/v2/catalog/object/');//add the item_id to the end
+				$product->setBatchDelete('/v2/catalog/batch-delete');
+				$this->apiEndpoints['product'] = $product;
+			}
+
+			protected function defineOrderEndpoints():void
+			{
+				$order = new APIEndpoint();
+				$order->setCreate('/v2/orders');
+				$order->setSearch('/v2/orders/search');
+				$order->setUpdate('/v2/orders/'); //add order_id
+				$this->apiEndpoints['order'] = $order;
+			}
+			protected function definePaymentEndpoints():void
+			{
+				$payment = new APIEndpoint();
+				$payment->setCreate('/v2/payments');
+
+				$this->apiEndpoints['payment'] = $payment;
+			}
 
 	protected function refreshAccessToken(OAuthCredentials $credentials): array
 	{
@@ -227,8 +284,275 @@
 
 	protected function setContentTypes(): void
 	{
-		// TODO: Implement setContentTypes() method.
+		$base = $this->getBaseFields();
+		$this->contentTypes = [
+			'customer'				=> $this->getCustomerFields(),
+			'REGULAR'				=> $base,
+			'FOOD_AND_BEV'			=> array_merge($base, $this->setFoodAndBevFields()),
+			'APPOINTMENTS_SERVICE'	=> array_merge($base, $this->setAppointmentServiceFields()),
+			'EVENT'					=> array_merge($base, $this->setEventFields()),
+			'GIFT_CARD'				=> array_merge($base, $this->setGiftCardFields()),
+		];
 	}
+		protected function getCustomerFields():array
+		{
+			return [
+				'address'	=> [
+					'type'	=> 'group',
+					'fields'	=> [
+						'address_line_1'	=> [
+							'type'	=> 'text',
+							'label'	=> 'Address Line 1',
+							'hint'	=> 'ex: 6551 111 St NW',
+							'required'	=> true,
+							'section'	=> 'address'
+						],
+						'address_line_2'	=> [
+							'type'	=> 'text',
+							'label'	=> 'Address Line 2',
+							'hint'	=> 'ex: Unit 2',
+							'section'	=> 'address'
+						],
+						'locality'	=> [
+							'type'	=> 'text',
+							'label'=> 'City',
+							'section'	=> 'address',
+							'required'	=> true,
+						],
+						'administrative_district_level_1' => [
+							'type'	=> 'text',
+							'label' => 'Province',
+							'hint' => 'The two-character code, example: AB',
+							'default'=> 'AB',
+							'section'	=> 'address',
+							'required'	=> true,
+						],
+						'postal_code' => [
+							'type'	=> 'text',
+							'label'	=> 'Postal Code',
+							'section'=> 'address'
+						],
+						'country'	=> [
+							'type'	=> 'text',
+							'label'	=> 'Country Code',
+							'hint'	=> 'The tw-character country code, example: CA',
+							'default'	=> 'CA',
+							'section'	=> 'address',
+							'required'	=> true,
+						],
+						'first_name'	=> [
+							'type'	=> 'text',
+							'label'	=> 'First Name (if different)',
+							'hint'	=> 'Optional field to save the address to someone that isn\'t you'
+						],
+						'last_name'	=> [
+							'type'	=> 'text',
+							'label'	=> 'Last Name (if different)',
+							'hint'	=> 'Optional field to save the address to someone that isn\'t you'
+						]
+					]
+				]
+			];
+		}
+		protected function getBaseFields():array
+		{
+			return [
+				'price' => [
+					'type'        => 'number',
+					'label'       => 'Price',
+					'step'        => 0.01,
+					'max'         => 99999,
+					'description' => 'Price for this variation'
+				],
+				'sku' => [
+					'type'        => 'text',
+					'label'       => 'SKU',
+					'description' => 'Stock keeping unit'
+				],
+				'cart_quantity'	=> [
+					'type'	=> 'number',
+					'label'	=> 'Quantity',
+					'hidden'	=> true,
+				],
+				'available_for_pickup' => [
+					'type'	=> 'true_false',
+					'label'	=> 'Available for Pick Up',
+					'section'=> 'square-advanced'
+				],
+				'available_online' => [
+					'type'	=> 'true_false',
+					'label'	=> 'Available online',
+					'section'=> 'square-advanced'
+				],
+				'product_variations' => [
+					'type'        => 'repeater',
+					'label'       => 'Product Variations',
+					'description' => 'Different versions of this product (sizes, colors, etc.)',
+					'add_label'   => 'Add Variation',
+					'section'     => 'variations',
+					'fields'      => $this->setVariationFields()
+				],
+			];
+		}
+			protected function setVariationFields(?string $type = null):array
+			{
+				$fields = [
+					'name' => [
+						'type'        => 'text',
+						'label'       => 'Variation Name',
+						'description' => 'e.g., "Small", "Large", "Red", etc.'
+					],
+					'sku' => [
+						'type'        => 'text',
+						'label'       => 'SKU',
+						'description' => 'Stock keeping unit'
+					],
+					'price' => [
+						'type'        => 'number',
+						'label'       => 'Price',
+						'step'        => 0.01,
+						'max'         => 99999,
+						'description' => 'Price for this variation'
+					],
+					'track_inventory'	=> [
+						'type'	=> 'true_false',
+						'label'	=> 'Track Inventory',
+					],
+					'item_id' => [
+						'type'        => 'text',
+						'label'       => 'Square Variation ID',
+						'description' => 'Square catalog ID for this variation',
+						'hidden'      => true
+					],
+					'last_sync' => [
+						'type'   => 'datetime',
+						'label'  => 'Last Sync',
+						'hidden' => true
+					]
+				];
+
+				switch ($type) {
+					case 'FOOD_AND_BEV':
+						$fields['ingredients']	= [
+							'type'	=> 'textarea',
+							'label'	=> 'Ingredients List',
+							'description'	=> 'Separate ingredients with commas',
+						];
+						$fields['preparation_time_duration']	= [
+							'type'	=> 'number',
+							'label'	=> 'Preparation time (in minutes)',
+						];
+						break;
+					case 'GIFT_CARD':
+						$fields['gift_card_type']	= [
+							'type'	=> 'select',
+							'label'	=> 'Gift Card Type',
+							'options'	=> [
+								'PHYSICAL'	=> 'Physical',
+								'DIGITAL'	=> 'Digital',
+							],
+							'default'	=> 'DIGITAL',
+						];
+						break;
+					case 'APPOINTMENTS_SERVICE':
+						$fields['service_duration']	= [
+							'type'	=> 'number',
+							'label'	=> 'Duration of Service in Minutes'
+						];
+						$fields['available_for_booking']	= [
+							'type'	=> 'true_false',
+							'label'	=> 'Available for Booking'
+						];
+						break;
+				}
+				return array_combine(
+					array_map(fn($k) => '_square_' . $k, array_keys($fields)),
+					$fields
+				);
+			}
+			protected function setFoodAndBevFields():array
+			{
+				return [
+					'ingredients'	=> [
+						'type'	=> 'textarea',
+						'label'	=> 'Ingredients',
+						'hint'	=> 'A comma separated list of ingredients'
+					],
+					'preparation_time_duration' => [
+						'label'	=> 'Preparation Time',
+						'type'	=> 'number',
+						'hint'	=> 'Preparation time in minutes'
+					],
+					'product_variations' => [
+						'type'        => 'repeater',
+						'label'       => 'Product Variations',
+						'description' => 'Different versions of this product (sizes, colors, etc.)',
+						'add_label'   => 'Add Variation',
+						'section'     => 'variations',
+						'fields'      => $this->setVariationFields('FOOD_AND_BEV')
+					],
+				];
+				/* TODO: Set definitions for:
+					'dietary_preferences'	=> [
+
+					],
+					'calories_text'	=> [
+
+					],
+				*/
+			}
+			protected function setAppointmentServiceFields():array
+			{
+				return [
+
+					'product_variations' => [
+						'type'        => 'repeater',
+						'label'       => 'Product Variations',
+						'description' => 'Different versions of this product (sizes, colors, etc.)',
+						'add_label'   => 'Add Variation',
+						'section'     => 'variations',
+						'fields'      => $this->setVariationFields('APPOINTMENTS_SERVICE')
+					],
+				];
+			}
+
+			protected function setEventFields():array
+			{
+				return [
+					'venue_details'	=> [
+						'type'	=> 'textarea',
+						'label'	=> 'Venue Details',
+					],
+					'capacity'	=> [
+						'type'	=> 'number',
+						'label'	=> 'Capacity'
+					],
+					'product_variations' => [
+						'type'        => 'repeater',
+						'label'       => 'Product Variations',
+						'description' => 'Different versions of this product (sizes, colors, etc.)',
+						'add_label'   => 'Add Variation',
+						'section'     => 'variations',
+						'fields'      => $this->setVariationFields('EVENT')
+					],
+				];
+			}
+			protected function setGiftCardFields():array
+			{
+				return [
+		//			'allowed_locations'	=> [
+		//
+		//			],
+					'product_variations' => [
+						'type'        => 'repeater',
+						'label'       => 'Product Variations',
+						'description' => 'Different versions of this product (sizes, colors, etc.)',
+						'add_label'   => 'Add Variation',
+						'section'     => 'variations',
+						'fields'      => $this->setVariationFields('GIFT_CARD')
+					],
+				];
+			}
 
 	protected function formatForService(int $itemID, string $type = 'post'): array
 	{
@@ -255,21 +579,28 @@
 					]
 				]
 			);
-			return $response['id'];
+			return $response['data'];
 		} catch (Exception $e) {
 			return false;
 		}
 	}
 		protected function handleEmailSearchResponse(WP_Error|array $response, string $method):array
 		{
-
+			$data = empty($response['customers'])
+				? false
+				: $response['customers'][0]??false;
+			return $this->response(true, 'Successfully got results.', $data);
 		}
 
 	protected function handleCreateUser(array $data): array
 	{
 		try {
 			return $this->postRequest(
-				sprintf('%s/v2/customers',$this->getBaseURL()),
+				sprintf(
+					'%s%s',
+					$this->getBaseURL(),
+					$this->apiEndpoints['customer']['create']->getEndpoint()
+				),
 				$data
 			);
 		} catch (Exception $e) {
@@ -278,7 +609,10 @@
 	}
 		protected function handleCreateUserResponse(WP_Error|array $response, string $method):array
 		{
-
+			$data = empty($response['customer'])
+				? false
+				: $response['customer'];
+			return $this->response(true, 'Successfully got results.', $data);
 		}
 	protected function validateUserFields(int $userID, array $fields):array|false
 	{
@@ -616,5 +950,16 @@
 		}
 	}
 
+	public function getAdditionalFields(?string $content_type = null):array
+	{
+		$this->setContentTypes();
+		if (is_null($content_type) || !array_key_exists($content_type, $this->contentTypes)) {
+			return [];
+		}
+		return $this->contentTypes[$content_type];
+	}
+
+
+
 
 }

--
Gitblit v1.10.0