From cea8981143c20ae34c7ef89754ce359b324691a4 Mon Sep 17 00:00:00 2001 From: japatel Date: Mon, 6 Oct 2014 11:17:39 -0500 Subject: [PATCH] Enabling Future Payments - Added feature to create future payments - Updated Authentication model to retrieve long lived refresh token - Updated Documentation - Updated Sample --- lib/PayPal/Api/FuturePayment.php | 48 +++++++++ lib/PayPal/Api/Payment.php | 16 +-- lib/PayPal/Auth/OAuthTokenCredential.php | 87 ++++++++++++--- sample/doc/payments/CreateFuturePayment.html | 70 +++++++++++++ sample/payments/CreateFuturePayment.php | 105 +++++++++++++++++++ 5 files changed, 303 insertions(+), 23 deletions(-) create mode 100644 lib/PayPal/Api/FuturePayment.php create mode 100644 sample/doc/payments/CreateFuturePayment.html create mode 100644 sample/payments/CreateFuturePayment.php diff --git a/lib/PayPal/Api/FuturePayment.php b/lib/PayPal/Api/FuturePayment.php new file mode 100644 index 00000000..5883a632 --- /dev/null +++ b/lib/PayPal/Api/FuturePayment.php @@ -0,0 +1,48 @@ +toJSON(); + $call = new PPRestCall($apiContext); + $json = $call->execute( + array('PayPal\Rest\RestHandler'), + "/v1/payments/payment", + "POST", + $payLoad, + [ + 'Paypal-Application-Correlation-Id' => $correlationId, + 'PAYPAL-CLIENT-METADATA-ID' => $correlationId + ] + ); + $this->fromJson($json); + + return $this; + + } +} diff --git a/lib/PayPal/Api/Payment.php b/lib/PayPal/Api/Payment.php index b601cef8..ddd26995 100644 --- a/lib/PayPal/Api/Payment.php +++ b/lib/PayPal/Api/Payment.php @@ -26,7 +26,7 @@ class Payment extends PPModel implements IResource /** * @var */ - private static $credential; + protected static $credential; /** * Set Credential @@ -467,14 +467,14 @@ public static function all($params, $apiContext = null) $payLoad = ""; $allowedParams = array( - 'count' => 1, - 'start_id' => 1, + 'count' => 1, + 'start_id' => 1, 'start_index' => 1, - 'start_time' => 1, - 'end_time' => 1, - 'payee_id' => 1, - 'sort_by' => 1, - 'sort_order' => 1, + 'start_time' => 1, + 'end_time' => 1, + 'payee_id' => 1, + 'sort_by' => 1, + 'sort_order' => 1, ); if ($apiContext == null) { diff --git a/lib/PayPal/Auth/OAuthTokenCredential.php b/lib/PayPal/Auth/OAuthTokenCredential.php index 36b6dd0e..f0d624f5 100644 --- a/lib/PayPal/Auth/OAuthTokenCredential.php +++ b/lib/PayPal/Auth/OAuthTokenCredential.php @@ -1,14 +1,11 @@ accessToken != null && (time() - $this->tokenCreateTime) > ($this->tokenExpiresIn - self::$expiryBufferTime)) { + if ( + $this->accessToken != null && + (time() - $this->tokenCreateTime) > ($this->tokenExpiresIn - self::$expiryBufferTime) + ) { $this->accessToken = null; } // If accessToken is Null, obtain a new token if ($this->accessToken == null) { - $this->_generateAccessToken($config); + $this->updateAccessToken($config); } return $this->accessToken; } /** - * Generates a new access token + * Get a Refresh Token from Authorization Code * * @param $config + * @param $authorizationCode + * @return string|null + */ + public function getRefreshToken($config, $authorizationCode) //Which comes from Mobile. + { + $payload = + "grant_type=authorization_code&code=". + $authorizationCode. + "&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=token"; + $jsonResponse = $this->getToken($config, $payload); + + if ($jsonResponse != null && isset($jsonResponse["refresh_token"])) { + return $jsonResponse['refresh_token']; + } + } + + /** + * Updates Access Token based on given input * - * @return null + * @param $config + * @param string|null $refreshToken + * @return string + */ + public function updateAccessToken($config, $refreshToken = null) + { + $this->generateAccessToken($config, $refreshToken); + return $this->accessToken; + } + + /** + * Retrieves the token based on the input configuration + * + * @param [] $config + * @param string $payload + * @return mixed + * @throws PPConfigurationException + * @throws \PayPal\Exception\PPConnectionException */ - private function _generateAccessToken($config) + private function getToken($config, $payload) { $base64ClientID = base64_encode($this->clientId . ":" . $this->clientSecret); $headers = array( @@ -126,20 +161,40 @@ private function _generateAccessToken($config) $httpConfiguration = $this->getOAuthHttpConfiguration($config); $httpConfiguration->setHeaders($headers); - $connection = PPConnectionManager::getInstance()->getConnection($httpConfiguration, $config); - $res = $connection->execute("grant_type=client_credentials"); + $connection = new PPHttpConnection($httpConfiguration, $config); + $res = $connection->execute($payload); $jsonResponse = json_decode($res, true); if ($jsonResponse == null || !isset($jsonResponse["access_token"]) || !isset($jsonResponse["expires_in"])) { $this->accessToken = null; $this->tokenExpiresIn = null; - $this->logger->warning("Could not generate new Access token. Invalid response from server: " . $jsonResponse); + $this->logger->warning( + "Could not generate new Access token. Invalid response from server: " . $jsonResponse + ); } else { $this->accessToken = $jsonResponse["access_token"]; $this->tokenExpiresIn = $jsonResponse["expires_in"]; } - $this->tokenCreateTime = time(); + return $jsonResponse; + } + + + /** + * Generates a new access token + * + * @param [] $config + * @return null + */ + private function generateAccessToken($config, $refreshToken = null) + { + $payload = "grant_type=client_credentials"; + if ($refreshToken != null) { + // If the refresh token is provided, it would get access token using refresh token + // Used for Future Payments + $payload = "grant_type=refresh_token&refresh_token=$refreshToken"; + } + $this->getToken($config, $payload); return $this->accessToken; } @@ -170,7 +225,9 @@ private function getOAuthHttpConfiguration($config) throw new PPConfigurationException('The mode config parameter must be set to either sandbox/live'); } } else { - throw new PPConfigurationException('You must set one of service.endpoint or mode parameters in your configuration'); + throw new PPConfigurationException( + 'You must set one of service.endpoint or mode parameters in your configuration' + ); } $baseEndpoint = rtrim(trim($baseEndpoint), '/'); diff --git a/sample/doc/payments/CreateFuturePayment.html b/sample/doc/payments/CreateFuturePayment.html new file mode 100644 index 00000000..b502fbfb --- /dev/null +++ b/sample/doc/payments/CreateFuturePayment.html @@ -0,0 +1,70 @@ +payments/CreateFuturePayment
sample/payments/CreateFuturePayment.php
<?php

Create Payment using PayPal as payment method

+

This sample code demonstrates how you can process a +PayPal Account based Payment. +API used: /v1/payments/payment

require __DIR__ . '/../bootstrap.php'; +use PayPal\Api\Amount; +use PayPal\Api\Details; +use PayPal\Api\Item; +use PayPal\Api\ItemList; +use PayPal\Api\Payer; +use PayPal\Api\Payment; +use PayPal\Api\RedirectUrls; +use PayPal\Api\Transaction; +session_start();

Payer

+

A resource representing a Payer that funds a payment +For paypal account payments, set payment method +to 'paypal'.

$payer = new Payer(); +$payer->setPaymentMethod("paypal");

Amount

+

Lets you specify a payment amount. +You can also specify additional details +such as shipping, tax.

$amount = new Amount(); +$amount->setCurrency("USD") + ->setTotal("0.17");

Transaction

+

A transaction defines the contract of a +payment - what is the payment for and who +is fulfilling it.

$transaction = new Transaction(); +$transaction->setAmount($amount) + ->setDescription("Payment description");

Redirect urls

+

Set the urls that the buyer must be redirected to after +payment approval/ cancellation.

$baseUrl = getBaseUrl(); +$redirectUrls = new RedirectUrls(); +$redirectUrls->setReturnUrl("$baseUrl/ExecutePayment.php?success=true") + ->setCancelUrl("$baseUrl/ExecutePayment.php?success=false");

Payment

+

A Payment Resource; create one using +the above types and intent set to 'sale'

$payment = new Payment(); +$payment->setIntent("authorize") + ->setPayer($payer) + ->setRedirectUrls($redirectUrls) + ->setTransactions(array($transaction));

Get Refresh Token

+

You need to get a permanent refresh token from the authorization code, retrieved from the mobile sdk.

authorization code from mobile sdk

$authorizationCode = 'EF4Ds2Wv1JbHiU_UuhR5v-ftTbeJD03RBX-Zjg9pLCAhdLqLeRR6YSKTNsrbQGX7lFoZ3SxwFyxADEZbBOxpn023W9SA0JzSQAy-9eLdON5eDPAyMyKlHyNVS2DqBR2iWVfQGfudbd9MDoRxMEjIZbY';

correlation id from mobile sdk

$correlationId = '123123456'; + +try {

Exchange authorization_code for long living refresh token. You should store +it in a database for later use

$refreshToken = $apiContext->getCredential()->getRefreshToken($apiContext->getConfig(), $authorizationCode);

Update the access token in apiContext

$apiContext->getCredential()->updateAccessToken($apiContext->getConfig(), $refreshToken);

Create Future Payment

+

Create a payment by calling the 'create' method +passing it a valid apiContext. +(See bootstrap.php for more on ApiContext) +The return object contains the state and the +url to which the buyer must be redirected to +for payment approval +Please note that currently future payments works only with Paypal as a funding instrument.

$payment->create($apiContext, $correlationId); + +} catch (PayPal\Exception\PPConnectionException $ex) { + echo "Exception: " . $ex->getMessage() . PHP_EOL; + var_dump($ex->getData()); + exit(1); +} +?> + +<html> +<head> + <title>Future payments</title> +</head> +<body> +<div> + Created payment: + <?php echo $payment->getId();?> +</div> +<pre><?php echo $payment->toJSON(JSON_PRETTY_PRINT);?></pre> +<a href='../index.html'>Back</a> +</body> +</html>
\ No newline at end of file diff --git a/sample/payments/CreateFuturePayment.php b/sample/payments/CreateFuturePayment.php new file mode 100644 index 00000000..66e6880f --- /dev/null +++ b/sample/payments/CreateFuturePayment.php @@ -0,0 +1,105 @@ +setPaymentMethod("paypal"); + +// ### Amount +// Lets you specify a payment amount. +// You can also specify additional details +// such as shipping, tax. +$amount = new Amount(); +$amount->setCurrency("USD") + ->setTotal("0.17"); + +// ### Transaction +// A transaction defines the contract of a +// payment - what is the payment for and who +// is fulfilling it. +$transaction = new Transaction(); +$transaction->setAmount($amount) + ->setDescription("Payment description"); + +// ### Redirect urls +// Set the urls that the buyer must be redirected to after +// payment approval/ cancellation. +$baseUrl = getBaseUrl(); +$redirectUrls = new RedirectUrls(); +$redirectUrls->setReturnUrl("$baseUrl/ExecutePayment.php?success=true") + ->setCancelUrl("$baseUrl/ExecutePayment.php?success=false"); + +// ### Payment +// A Payment Resource; create one using +// the above types and intent set to 'sale' +$payment = new Payment(); +$payment->setIntent("authorize") + ->setPayer($payer) + ->setRedirectUrls($redirectUrls) + ->setTransactions(array($transaction)); + +// ### Get Refresh Token +// You need to get a permanent refresh token from the authorization code, retrieved from the mobile sdk. + +// authorization code from mobile sdk +$authorizationCode = 'EF4Ds2Wv1JbHiU_UuhR5v-ftTbeJD03RBX-Zjg9pLCAhdLqLeRR6YSKTNsrbQGX7lFoZ3SxwFyxADEZbBOxpn023W9SA0JzSQAy-9eLdON5eDPAyMyKlHyNVS2DqBR2iWVfQGfudbd9MDoRxMEjIZbY'; + +// correlation id from mobile sdk +$correlationId = '123123456'; + +try { + // Exchange authorization_code for long living refresh token. You should store + // it in a database for later use + $refreshToken = $apiContext->getCredential()->getRefreshToken($apiContext->getConfig(), $authorizationCode); + + // Update the access token in apiContext + $apiContext->getCredential()->updateAccessToken($apiContext->getConfig(), $refreshToken); + + // ### Create Future Payment + // Create a payment by calling the 'create' method + // passing it a valid apiContext. + // (See bootstrap.php for more on `ApiContext`) + // The return object contains the state and the + // url to which the buyer must be redirected to + // for payment approval + // Please note that currently future payments works only with Paypal as a funding instrument. + $payment->create($apiContext, $correlationId); + +} catch (PayPal\Exception\PPConnectionException $ex) { + echo "Exception: " . $ex->getMessage() . PHP_EOL; + var_dump($ex->getData()); + exit(1); +} +?> + + + + Future payments + + +
+ Created payment: + getId();?> +
+
toJSON(JSON_PRETTY_PRINT);?>
+Back + +