소스 검색

First testmode transaction success

Richard Knight 6 년 전
부모
커밋
7c5a985c07

+ 3 - 0
config/config.yml.dist

@@ -9,5 +9,8 @@ sq_sandbox_app_id: sandbox-sq0idp-E62fjwNzSQG08kHHzOhc7w
 sq_sandbox_token: sandbox-sq0atb-pDGW0n945W5jLLIA4eUhpQ
 sq_sandbox_location_id: CBASEC73OwdNXqWhk6o3SKFwsvUgAQ
 
+testmode: true
+
+
 
 

+ 56 - 4
src/Controller/SquareBackendController.php

@@ -26,7 +26,7 @@ class SquareBackendController extends Base
 
         // Create and configure a new API client object
         $apiConfig = new \SquareConnect\Configuration();
-        $apiConfig->setAccessToken($config['sq_sandbox_token']);
+        $apiConfig->setAccessToken($config['sq_app_secret']);
         $this->apiClient = new \SquareConnect\ApiClient($apiConfig);
     }    
     
@@ -34,6 +34,7 @@ class SquareBackendController extends Base
     {
         $collection->match('/', [$this, 'squareDashboard'])->before([$this, 'checkUserPermissions']);
         $collection->match('/request-oauth-token', [$this, 'oauthRequestToken'])->before([$this, 'checkUserPermissions']);
+        $collection->match('/revoke-oauth-token', [$this, 'oauthRevokeToken'])->before([$this, 'checkUserPermissions']);
         return $collection;
     }
 
@@ -78,7 +79,7 @@ class SquareBackendController extends Base
         return $this->render('@Squareback/authorised.twig', ['token' => $oauthToken]);
     }
 
-    // ------------------------------------------------------------------------------------------------------------------------------------------
+    // -----------------------------------------------------------------------------------------------------------------
 
 	public function checkUserPermissions()
 	{
@@ -91,7 +92,8 @@ class SquareBackendController extends Base
 	
 	private function getOAuthToken($authorizationCode) {
         // Exchange the authorization code for an OAuth token
-        // Create an OAuth API client
+		
+		// Create an OAuth API client
         $oauthApi = new \SquareConnect\Api\OAuthApi($this->apiClient);
         $body = new \SquareConnect\Model\ObtainTokenRequest();
       
@@ -106,6 +108,56 @@ class SquareBackendController extends Base
             throw new Exception('Error Processing Request: Token exchange failed!', 1);
         }
         return $result->getAccessToken();
-    }
+	}
+	
+	public function oauthRevokeToken() {
+		$manager = $this->app['filesystem'];
+		if (!$manager->hasFilesystem('extensions_config')) {
+			throw new Exception('Could not find filesystem extensions_config');
+		}
+		$filesystem = $manager->getFilesystem('extensions_config');
+		$path = '.sqoatoken';
+		$file = $filesystem->getFile($path);
+		if (!$file->exists($path)) {
+			throw new Exception('Could not find '.$path);
+		}
+		$oauthToken = $file->read($path);
+
+		// Create an OAuth API client
+		/*
+		$oauthApi = new \SquareConnect\Api\OAuthApi($this->apiClient);
+		$body = new \SquareConnect\Model\RevokeTokenRequest();
+
+		// Set the POST body
+		$body->setClientId($this->config['sq_app_id']);
+		$body->setAccessToken($oauthToken);
+		try {
+			$result = $oauthApi->revokeToken($body);
+			$filesytem->delete($path);
+		} catch (Exception $e) {
+			error_log('Exception when calling OAuthApi->revokeToken: ' . $e->getMessage());
+			throw new Exception('Error Processing Request: Token revocation failed!', 1);
+		}
+		*/
+
+		// Revoke the token - alternative method (as above didn't work)
+		$url = 'https://connect.squareup.com/oauth2/revoke';
+		$data = array(
+			'access_token' => $oauthToken,
+			'client_id' => $this->config['sq_app_id']
+		);
+		$options = array(
+			'http' => array(
+				'header'  => "Content-type: application/json\r\n".  
+				"Authorization: Client ".$this->config['sq_app_secret']."\r\n",
+				'method'  => 'POST',
+				'content' => json_encode($data)
+			)
+		);
+		$context = stream_context_create($options);
+		$result = file_get_contents($url, false, $context);
+		$filesytem->delete($path);
+        return $this->render('@Squareback/revoked.twig');
+	}
 
 }

+ 104 - 6
src/SquarepayExtension.php

@@ -24,8 +24,7 @@ class SquarepayExtension extends SimpleExtension
 	
 	protected function registerServices(Application $app)
 	{
-        $app['square.apiClient'] = $app->share(function($app) {
-			
+		$app['square.apiClient'] = $app->share(function($app) {
 			// Create and configure a new Square API client using the OAuth token
 			$manager = $app['filesystem'];
 			if (!$manager->hasFilesystem('extensions_config')) {
@@ -45,6 +44,17 @@ class SquarepayExtension extends SimpleExtension
 			return new \SquareConnect\ApiClient($apiConfig);
 		});
 
+		$config = $this->getConfig();
+		if ($config['testmode']) {
+			$app['square.apiSandboxClient'] = $app->share(function($app) use ($config) {
+				// Create and configure a new Square API client using the OAuth token
+				$apiConfig = new \SquareConnect\Configuration();
+				$apiConfig->setAccessToken($config['sq_sandbox_token']);
+				$apiClient = new \SquareConnect\ApiClient($apiConfig);
+				return new \SquareConnect\ApiClient($apiConfig);
+			});
+		}
+
 		$app['twig.runtime.square'] = $app->share(function ($app) {
 			return new Twig\SquareTwigRuntime(
 				$app['square.apiClient'],
@@ -121,6 +131,7 @@ class SquarepayExtension extends SimpleExtension
 		$sku	= $request->request->get('sku');
 		$name	= $request->request->get('name');
 		$price	= $request->request->get('price');
+		$squid	= $request->request->get('squid'); // Square Unique Id (for CatalogItemVariation)
 		$key	= substr(md5($sku), 0, 10);
 		if (isset($basket[$key])) {
 			$basket[$key]['quantity']++;
@@ -131,7 +142,8 @@ class SquarepayExtension extends SimpleExtension
 				'name'		=> $name,
 				'price'		=> $price,
 				'quantity'	=> 1,
-				'total'		=> $price
+				'total'		=> $price,
+				'squid'		=> $squid
 			];
 		}
         $app['session']->set('basket', $basket);
@@ -171,15 +183,101 @@ class SquarepayExtension extends SimpleExtension
 
 	public function basketClear(Application $app)
 	{
-        $app['session']->remove('basket');
+        $app['session']->set('basket', []);
         return new RedirectResponse('/basket');
 	}
 
 	// -----------------------------------------------------------------------------------------------------------------
 	// SQUARE PAYMENT PROCESSING
 
-	public function processSquarePaymentResponse() {
-		// TODO
+	public function processSquarePaymentResponse(Application $app, Request $request) {
+		
+		// Grab the card nonce, name and email
+		$cardNonce = $request->request->get('nonce');
+		$name = $request->request->get('name');
+		$email = $request->request->get('email');
+		
+		$config = $this->getConfig();
+		$testmode = $config['testmode'];
+		$locationId = $testmode ? $config['sq_sandbox_location_id'] : $config['sq_location_id'];
+		$apiClient = $testmode ? $app['square.apiSandboxClient'] : $app['square.apiClient'];
+
+		// Create the order
+		// NOTE: The Orders API has sandbox support for ad-hoc items only. There is no sandbox support for orders built from Catalog items.
+		$orderId = null;
+		$basket	= $app['session']->get('basket');
+		$lineItems = [];
+		foreach($basket as $line) {
+			$sqitem = new \SquareConnect\Model\CreateOrderRequestLineItem;
+			if ($config['testmode']) {
+				$sqitem->setName($line['name']);
+			} else {
+				$sqitem->setCatalogObjectId($line['squid']);
+			}
+			$sqitem->setQuantity((string) $line['quantity']);
+			$price = new \SquareConnect\Model\Money;
+			$price->setAmount((int) $line['price']);
+			$price->setCurrency('GBP');
+			$sqitem->setBasePriceMoney($price);
+			array_push($lineItems, $sqitem);
+		}
+		$request = new \SquareConnect\Model\CreateOrderRequest();
+		$request->setIdempotencyKey(uniqid()); // uniqid() generates a random string
+		$request->setLineItems($lineItems);
+		try {
+			$ordersApi = new \SquareConnect\Api\OrdersApi($apiClient);
+			$response = $ordersApi->createOrder($locationId, $request);
+			dump($response);
+		}
+		catch (Exception $e) {
+			// TODO: Add better error handling
+			echo '<pre>';
+			echo 'Exception when calling OrdersApi->createOrder:', $e->getMessage(), PHP_EOL;
+			echo '</pre>';
+			exit;
+		}
+		$orderId = $response['order']['id'];
+		dump($orderId);
+
+		// Build transaction request
+		$buyerInfo = [
+			'buyer_email_address' => $email
+		];
+
+		$idempotencyKey = uniqid();
+		$basketTotal = array_sum(array_column($basket, 'total'));
+		$paymentInfo = [
+			'idempotency_key' => $idempotencyKey,
+			'amount_money' => [
+				'amount' => $basketTotal,
+				'currency' => 'GBP'
+			],
+			'card_nonce' => $cardNonce,
+		];
+		if ($orderId) {
+			$paymentInfo['order_id'] = $orderId;
+		}
+		
+		$referenceInfo = [
+			'buyer_name' => $name,
+			'buyer_email_address' => $email
+		];
+
+		// $chargeRequest = new \SquareConnect\Model\ChargeRequest();
+		// $chargeRequest->setOrderId($orderId); // Link an order ID
+
+		$tranactionRequest = array_merge($buyerInfo, $paymentInfo, $referenceInfo);
+		$transactionsApi = new \SquareConnect\Api\TransactionsApi($apiClient);
+		try {
+			$response = $transactionsApi->charge($locationId, $tranactionRequest);
+			dump($response);
+		} catch (\SquareConnect\ApiException $e) {
+			echo "<hr>" .
+				 "The SquareConnect\Api\TransactionsApi object threw an exception.<br>" .
+				 "API call: <code>TransactionsApi->charge</code>" .
+				 "<pre>" . var_dump($e) . "</pre>";
+			throw $e;
+		}
 	}
 
 }

+ 6 - 8
src/Twig/SquareTwigRuntime.php

@@ -26,18 +26,18 @@ class SquareTwigRuntime
 	{
 		try {
 			$catalogApi = new \SquareConnect\Api\CatalogApi($this->apiClient);
-			$products = $catalogApi->listCatalog();
+			$response = $catalogApi->listCatalog();
 		} catch (Exception $e) {
 			error_log($e->getMessage());
 			return 'ERROR: '.$e->getMessage();
 		}
-		$response = [];
-		foreach($products['objects'] as $p) {
+		$products = [];
+		foreach($response['objects'] as $p) {
 			if ($p['type'] === 'ITEM') {
-				array_push($response, $p);
+				array_push($products, $p);
 			}
 		}
-		return $response;
+		return $products;
 	}
 	
 	public function getBasket()
@@ -49,9 +49,7 @@ class SquareTwigRuntime
 	}
 	
 	public function displayCCForm() {
-		$context = $this->config + [
-			'testmode' => true
-		];
+		$context = $this->config;
 		return $this->twig->render('@Squarefront/cardentryform.twig', $context);
 	}
 

+ 4 - 3
templates/backend/authorised.twig

@@ -4,8 +4,9 @@
 
 {% block page_main %}
 
-	<p>
-	OAuth token is <b>{{ token }}</b>.
-	</p>
+	<div class="alert alert-success alert-dismissible">
+        <button type="button" class="close" data-dismiss="alert">×</button>
+         OAuth token is <b>{{ token }}</b>
+    </div>
 
 {% endblock %}

+ 1 - 0
templates/backend/dashboard.twig

@@ -11,6 +11,7 @@
 	<br>
 
 	<a href="{{ auth_link }}" class="btn btn-primary">Authorise Site</a>
+	<a href="square/revoke-oauth-token" class="btn btn-danger">Revoke Access</a>
 
 	<br><br>
 	{{ dump(config) }}

+ 6 - 0
templates/backend/revoked.twig

@@ -0,0 +1,6 @@
+{% extends "_base/_page-nav.twig" %}
+
+{% block page_title __('Squarepay access has been revoked') %}
+
+{% block page_main %}
+{% endblock %}

+ 4 - 0
templates/frontend/cardentryform.twig

@@ -14,6 +14,10 @@ var locationId = '{{ testmode ? sq_sandbox_location_id : sq_location_id }}';
 		<label>Name</label>
 		<input type="text" name="name">
 	</div>
+	<div class="cc-row">
+		<label>Email</label>
+		<input type="email" name="email">
+	</div>
 	<div class="cc-row">
 		<label>Card Number</label>
 		<div id="sq-card-number"></div>

+ 1 - 2
web/sq-paymentform.js

@@ -35,7 +35,7 @@ function init() {
 		},
 		cvv: {
 			elementId: 'sq-cvv',
-			placeholder: 'CVV'
+			placeholder: ''
 		},
 		expirationDate: {
 			elementId: 'sq-expiration-date',
@@ -64,7 +64,6 @@ function init() {
 					});
 					return;
 				}
-				alert('Nonce received: ' + nonce); /* FOR TESTING ONLY */
 				document.getElementById('card-nonce').value = nonce; // Assign the nonce value to the hidden form field
 				document.getElementById('nonce-form').submit();	// POST the nonce form to the payment processing page
 			}