diff --git a/README.md b/README.md index 29c9914a..55a809d3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ - [Introduction](#introduction) - [Installation](#installation) - [Usage](#usage) +- [Handling PayPal IPN](#paypalipn) - [Support](#support) @@ -10,7 +11,7 @@ **This is an experimental release.!** -Laravel plugin For Processing Payments Through Paypal. +Laravel plugin For Processing Payments Through Paypal. Using this plugin you can process or refund payments and handle IPN (Instant Payment Notification) from PayPal in your Laravel application. **Currently only PayPal Express Checkout Is Supported.** @@ -91,12 +92,50 @@ $response = PayPal::getExpressCheckoutDetails($token); * DoExpressCheckoutPayment ``` -$response = PayPal::doExpressCheckoutPayment($token,$PayerID); +$response = PayPal::doExpressCheckoutPayment($data, $token, $PayerID); // Note that 'token', 'PayerID' are values returned by PayPal when it redirects to success page after successful verification of user's PayPal info. ``` +* RefundTransaction +``` +$response = PayPal::refundTransaction($transactionid); +``` + + +## Handling PayPal IPN + +Included in this package is controller **PayPalIPNController**. This demo controller includes code on handling Instant Payment Notifications from PayPal, and saves the IPN response in session as **paypal_ipn_response**. +You can use this in your application like this: + +* Open **App\Http\Middleware\VerifyCsrfToken.php** and add your IPN route to **$excluded** routes variable. +``` +'notify' +``` + +* You can also extend it using your own controller like this: + +``` +class IPNController extends PayPalIPNController +{ + public function postNotify(Request $request) + { + parent::postNotify($request); + + $response = Session::get('paypal_ipn_response'); + + // Do your processing on IPN response + } +} +``` + ## Support -This plugin only supports Laravel 5 & Laravel 5.1 +This plugin only supports Laravel 5 & Laravel 5.1. +* In case of any issues, kindly create one on the [Issues](https://github.com/srmklive/laravel-paypal/issues) section. +* If you would like to contribute: + * Fork this repository. + * Implement your features. + * Generate pull request. + \ No newline at end of file diff --git a/config/config.php b/config/config.php index dbc04827..98d31cee 100644 --- a/config/config.php +++ b/config/config.php @@ -4,7 +4,7 @@ * Created by Raza Mehdi */ -return array( +return [ 'mode' => 'sandbox', // Can only be 'sandbox' Or 'live'. If empty or invalid, 'live' will be used. 'sandbox' => [ 'username' => '', @@ -21,4 +21,5 @@ 'payment_action' => 'Sale', // Can Only Be 'Sale', 'Authorization', 'Order' 'currency' => 'USD', -); \ No newline at end of file + 'notify_url' => url('paypal/notify'), // Change this accordingly for your application. +]; \ No newline at end of file diff --git a/src/ExpressCheckout.php b/src/ExpressCheckout.php index 4d1384fc..3b7028ba 100644 --- a/src/ExpressCheckout.php +++ b/src/ExpressCheckout.php @@ -1,68 +1,17 @@ setConfig(); - } - - /** - * Function To Set PayPal API Configuration - */ - private static function setConfig() - { - $paypal = config('paypal'); - - // Setting Default PayPal Mode If not set - if (empty($paypal['mode']) || !in_array($paypal['mode'], ['sandbox', 'live'])) { - $paypal['mode'] = 'live'; - } - - $mode = $paypal['mode']; - - // Getting PayPal API Credentials - foreach ($paypal[$mode] as $key=>$value) { - self::$config[$key] = $value; - } - - // Setting API Endpoints - if ($paypal['mode'] == 'sandbox') { - self::$config['api_url'] = !empty(self::$config['secret']) ? - 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api.sandbox.paypal.com/nvp'; - - self::$config['gateway_url'] = 'https://www.sandbox.paypal.com'; - } else { - self::$config['api_url'] = !empty(self::$config['secret']) ? - 'https://api-3t.paypal.com/nvp' : 'https://api.paypal.com/nvp'; - - self::$config['gateway_url'] = 'https://www.paypal.com'; - } - - unset($paypal); + $this->setConfig(); } /** @@ -162,7 +111,7 @@ public static function doExpressCheckoutPayment($data, $token, $payerid) 'PAYMENTREQUEST_0_CURRENCYCODE' => !empty(self::$config['currency']) ? self::$config['currency'] : 'USD', 'PAYMENTREQUEST_0_DESC' => $data['invoice_description'], 'PAYMENTREQUEST_0_INVNUM' => $data['invoice_id'], - 'PAYMENTREQUEST_0_NOTIFYURL' => $data['notify_url'] + 'PAYMENTREQUEST_0_NOTIFYURL' => config('paypal.notify_url') ]; foreach ($tmp as $k=>$v) { @@ -174,83 +123,4 @@ public static function doExpressCheckoutPayment($data, $token, $payerid) return $response; } - /** - * Function To Perform PayPal API Request - * - * @param $method - * @param $params - * @return array - */ - private static function doPayPalRequest($method, $params) - { - if (empty(self::$config)) - self::setConfig(); - - // Setting API Credentials, Version & Method - $post = [ - 'USER' => self::$config['username'], - 'PWD' => self::$config['password'], - 'SIGNATURE' => self::$config['secret'], - 'VERSION' => 123, - 'METHOD' => $method, - ]; - - // Checking Whether The Request Is PayPal IPN Response - if ($method == 'verifyipn') { - unset($post['method']); - - $post_url = self::$config['gateway_url'].'/cgi-bin/webscr'; - } else { - $post_url = self::$config['api_url']; - } - - foreach ($params as $key=>$value) { - $post[$key] = $value; - } - - try { - $request = self::$client->post($post_url, [ - 'form_params' => $post - ]); - - $response = $request->getBody(true); - $response = self::retrieveData($response); - - if ($method == 'SetExpressCheckout') { - if (!empty($response['TOKEN'])) { - $response['paypal_link'] = self::$config['gateway_url'] . - '/webscr?cmd=_express-checkout&token=' . $response['TOKEN']; - } else { - return [ - 'type' => 'error', - 'message' => trans('paypal::error.paypal_connection_error') - ]; - } - } - - return $response; - - } catch (ClientException $e) { - $message = $e->getRequest() . " " . $e->getResponse(); - } catch (ServerException $e) { - $message = $e->getRequest(). " " . $e->getResponse(); - } catch (BadResponseException $e) { - $message = $e->getRequest(). " " . $e->getResponse(); - } - - return [ - 'type' => 'error', - 'message' => $message - ]; - } - - /** - * Parse PayPal NVP Response - */ - private static function retrieveData($string) - { - $response = array(); - parse_str($string, $response); - return $response; - } } diff --git a/src/PayPalIPNController.php b/src/PayPalIPNController.php new file mode 100644 index 00000000..bf5df1af --- /dev/null +++ b/src/PayPalIPNController.php @@ -0,0 +1,31 @@ +all(); + + foreach($request_params as $key=>$value) + $post[$key] = $value; + + $post['cmd'] = '_notify-validate'; + + $response = self::verifyIPN($post); + + Session::put('paypal_ipn_response', $response); + } + +} diff --git a/src/PayPalRequestTrait.php b/src/PayPalRequestTrait.php new file mode 100644 index 00000000..abaf7b2e --- /dev/null +++ b/src/PayPalRequestTrait.php @@ -0,0 +1,165 @@ +$value) { + self::$config[$key] = $value; + } + + // Setting API Endpoints + if ($paypal['mode'] == 'sandbox') { + self::$config['api_url'] = !empty(self::$config['secret']) ? + 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api.sandbox.paypal.com/nvp'; + + self::$config['gateway_url'] = 'https://www.sandbox.paypal.com'; + } else { + self::$config['api_url'] = !empty(self::$config['secret']) ? + 'https://api-3t.paypal.com/nvp' : 'https://api.paypal.com/nvp'; + + self::$config['gateway_url'] = 'https://www.paypal.com'; + } + + unset($paypal); + } + + /** + * Verify IPNDetails + */ + private static function verifyIPN($post) + { + $response = self::doPayPalRequest('verifyipn',$post); + + return $response; + } + + /** + * Refund PayPal Transaction + */ + private static function refundTransaction($transaction) + { + $post = [ + 'TRANSACTIONID' => $transaction + ]; + + $response = self::doPayPalRequest('RefundTransaction',$post); + + return $response; + } + + /** + * Function To Perform PayPal API Request + * + * @param $method + * @param $params + * @return array + */ + private static function doPayPalRequest($method, $params) + { + if (empty(self::$config)) + self::setConfig(); + + // Setting API Credentials, Version & Method + $post = [ + 'USER' => self::$config['username'], + 'PWD' => self::$config['password'], + 'SIGNATURE' => self::$config['secret'], + 'VERSION' => 123, + 'METHOD' => $method, + ]; + + // Checking Whether The Request Is PayPal IPN Response + if ($method == 'verifyipn') { + unset($post['method']); + + $post_url = self::$config['gateway_url'].'/cgi-bin/webscr'; + } else { + $post_url = self::$config['api_url']; + } + + foreach ($params as $key=>$value) { + $post[$key] = $value; + } + + try { + $request = self::$client->post($post_url, [ + 'form_params' => $post + ]); + + $response = $request->getBody(true); + $response = self::retrieveData($response); + + if ($method == 'SetExpressCheckout') { + if (!empty($response['TOKEN'])) { + $response['paypal_link'] = self::$config['gateway_url'] . + '/webscr?cmd=_express-checkout&token=' . $response['TOKEN']; + } else { + return [ + 'type' => 'error', + 'message' => trans('paypal::error.paypal_connection_error') + ]; + } + } + + return $response; + + } catch (ClientException $e) { + $message = $e->getRequest() . " " . $e->getResponse(); + } catch (ServerException $e) { + $message = $e->getRequest(). " " . $e->getResponse(); + } catch (BadResponseException $e) { + $message = $e->getRequest(). " " . $e->getResponse(); + } + + return [ + 'type' => 'error', + 'message' => $message + ]; + } + + /** + * Parse PayPal NVP Response + */ + private static function retrieveData($string) + { + $response = array(); + parse_str($string, $response); + return $response; + } + +} \ No newline at end of file