diff --git a/src/Message/RestAuthorizeRequest.php b/src/Message/RestAuthorizeRequest.php index 2d61171..c75db20 100644 --- a/src/Message/RestAuthorizeRequest.php +++ b/src/Message/RestAuthorizeRequest.php @@ -15,7 +15,9 @@ * set to "authorize" (to authorize a payment to be captured later) rather than * "sale" (which is used to capture a payment immediately). * - * Example: + * ### Example + * + * #### Initialize Gateway * * * // Create a gateway for the PayPal RestGateway @@ -28,7 +30,17 @@ * 'secret' => 'MyPayPalSecret', * 'testMode' => true, // Or false when you are ready for live transactions * )); + * + * + * #### Direct Credit Card Authorize * + * This is for the use case where a customer has presented their + * credit card details and you intend to use the PayPal REST gateway + * for processing a transaction using that credit card data. + * + * This does not require the customer to have a PayPal account. + * + * * // Create a credit card object * // DO NOT USE THESE CARD VALUES -- substitute your own * // see the documentation in the class header. @@ -66,6 +78,135 @@ * As of January 2015 these transactions are only supported in the UK * and in the USA. * + * #### PayPal Account Authorization + * + * This is for the use case where the customer intends to pay using their + * PayPal account. Note that no credit card details are provided, instead + * both a return URL and a cancel URL are required. + * + * The optimal solution here is to provide a unique return URL and cancel + * URL per transaction. That way your code will know what transaction is + * being returned or cancelled by PayPal. + * + * So step 1 is to store some transaction data somewhere on your system so + * that you have an ID when your transaction returns. How you do this of + * course depends on what framework, database layer, etc, you are using but + * for this step let's assume that you have a class set up that can save + * a transaction and return the object, and that you can retrieve the ID + * of that saved object using some call like getId() on the object. Most + * ORMs such as Doctrine ORM, Propel or Eloquent will have some methods + * that will allow you to do this or something similar. + * + * + * $transaction = MyClass::saveTransaction($some_data); + * $txn_id = $transaction->getId(); + * + * + * Step 2 is to send the purchase request. + * + * + * // Do a purchase transaction on the gateway + * try { + * $transaction = $gateway->authorize(array( + * 'amount' => '10.00', + * 'currency' => 'AUD', + * 'description' => 'This is a test authorize transaction.', + * 'returnUrl' => 'http://mysite.com/paypal/return/?txn_id=' . $txn_id, + * 'cancelUrl' => 'http://mysite.com/paypal/return/?txn_id=' . $txn_id, + * )); + * $response = $transaction->send(); + * $data = $response->getData(); + * echo "Gateway purchase response data == " . print_r($data, true) . "\n"; + * + * if ($response->isSuccessful()) { + * echo "Step 2 was successful!\n"; + * } + * + * } catch (\Exception $e) { + * echo "Exception caught while attempting authorize.\n"; + * echo "Exception type == " . get_class($e) . "\n"; + * echo "Message == " . $e->getMessage() . "\n"; + * } + * + * + * Step 3 is where your code needs to redirect the customer to the PayPal + * gateway so that the customer can sign in to their PayPal account and + * agree to authorize the payment. The response will implement an interface + * called RedirectResponseInterface from which the redirect URL can be obtained. + * + * How you do this redirect is up to your platform, code or framework at + * this point. For the below example I will assume that there is a + * function called redirectTo() which can handle it for you. + * + * + * if ($response->isRedirect()) { + * // Redirect the customer to PayPal so that they can sign in and + * // authorize the payment. + * echo "The transaction is a redirect"; + * redirectTo($response->getRedirectUrl()); + * } + * + * + * Step 4 is where the customer returns to your site. This will happen on + * either the returnUrl or the cancelUrl, that you provided in the purchase() + * call. + * + * If the cancelUrl is called then you can assume that the customer has not + * authorized the payment, therefore you can cancel the transaction. + * + * If the returnUrl is called, then you need to complete the transaction via + * a further call to PayPal. + * + * Note this example assumes that the authorize has been successful. + * + * The payer ID and the payment ID returned from the callback after the authorize + * will be passed to the return URL as GET parameters payerId and paymentId + * respectively. + * + * + * $paymentId = $_GET['paymentId']; + * $payerId = $_GET['payerId']; + * + * // Once the transaction has been approved, we need to complete it. + * $transaction = $gateway->completePurchase(array( + * 'payer_id' => $payer_id, + * 'transactionReference' => $sale_id, + * )); + * $response = $transaction->send(); + * if ($response->isSuccessful()) { + * // The customer has successfully paid. + * echo "Step 4 was successful!\n"; + * } else { + * // There was an error returned by completePurchase(). You should + * // check the error code and message from PayPal, which may be something + * // like "card declined", etc. + * } + * + * + * #### Note on Handling Error Messages + * + * PayPal account payments are a 2 step process. Firstly the customer needs to + * authorize the payment from PayPal to your application. Secondly, assuming that + * the customer does not have enough balance to pay the invoice from their PayPal + * balance, PayPal needs to transfer the funds from the customer's credit card to + * their PayPal account. This transaction is between PayPal and the customer, and + * not between the customer and you. + * + * If the second transaction fails then a call to completePurchase() will return + * an error. However this error message will be fairly generic. For privacy + * reasons, PayPal will not disclose to the merchant the full reason for the + * failure, they will only disclose this to the customer. + * + * Therefore on a failed completeAuthorize() call you could display an error message + * like this one: + * + * "PayPal failed to process the transaction from your card. For privacy reasons, + * PayPal are unable to disclose to us the reason for this failure. You should try + * a different payment method, a different card within PayPal, or contact PayPal + * support if you need to understand the reason for the failed transaction. PayPal + * may advise you to use a different card if the particular card is rejected + * by the card issuer." + * * @link https://developer.paypal.com/docs/integration/direct/capture-payment/#authorize-the-payment * @link https://developer.paypal.com/docs/api/#authorizations * @link http://bit.ly/1wUQ33R diff --git a/src/Message/RestCaptureRequest.php b/src/Message/RestCaptureRequest.php index 98bc7b2..7db7e38 100644 --- a/src/Message/RestCaptureRequest.php +++ b/src/Message/RestCaptureRequest.php @@ -18,7 +18,9 @@ * indicate a final capture (prevent future captures) by setting the is_final_capture * value to true. * - * Example -- note this example assumes that the authorization has been successful + * ### Example + * + * Note this example assumes that the authorization has been successful * and that the authorization ID returned from the authorization is held in $auth_id. * See RestAuthorizeRequest for the first part of this example transaction: * diff --git a/src/Message/RestCompletePurchaseRequest.php b/src/Message/RestCompletePurchaseRequest.php index b265ba2..b246fce 100644 --- a/src/Message/RestCompletePurchaseRequest.php +++ b/src/Message/RestCompletePurchaseRequest.php @@ -15,19 +15,31 @@ * This call only works after a buyer has approved the payment using the * provided PayPal approval URL. * - * Example -- note this example assumes that the purchase has been successful - * and that the payer ID returned from the callback after the purchase is held - * in $payer_id, and that the transaction ID returned by the initial payment is - * held in $sale_id + * ### Example + * + * The payer ID and the payment ID returned from the callback after the purchase + * will be passed to the return URL as GET parameters payerId and paymentId + * respectively. + * * See RestPurchaseRequest for the first part of this example transaction: * * + * $paymentId = $_GET['paymentId']; + * $payerId = $_GET['payerId']; + * * // Once the transaction has been approved, we need to complete it. * $transaction = $gateway->completePurchase(array( * 'payer_id' => $payer_id, * 'transactionReference' => $sale_id, * )); * $response = $transaction->send(); + * if ($response->isSuccessful()) { + * // The customer has successfully paid. + * } else { + * // There was an error returned by completePurchase(). You should + * // check the error code and message from PayPal, which may be something + * // like "card declined", etc. + * } * * * @see RestPurchaseRequest diff --git a/src/Message/RestPurchaseRequest.php b/src/Message/RestPurchaseRequest.php index f12446a..75b0100 100644 --- a/src/Message/RestPurchaseRequest.php +++ b/src/Message/RestPurchaseRequest.php @@ -19,7 +19,9 @@ * extending the RestAuthorizeRequest class and simply over-riding * the getData() function to set the intent to sale. * - * Example: + * ### Example + * + * #### Initialize Gateway * * * // Create a gateway for the PayPal RestGateway @@ -32,7 +34,17 @@ * 'secret' => 'MyPayPalSecret', * 'testMode' => true, // Or false when you are ready for live transactions * )); + * + * + * #### Direct Credit Card Payment * + * This is for the use case where a customer has presented their + * credit card details and you intend to use the PayPal REST gateway + * for processing a transaction using that credit card data. + * + * This does not require the customer to have a PayPal account. + * + * * // Create a credit card object * // DO NOT USE THESE CARD VALUES -- substitute your own * // see the documentation in the class header. @@ -50,18 +62,25 @@ * 'billingState' => 'QLD', * )); * - * // Do an authorisation transaction on the gateway - * $transaction = $gateway->purchase(array( - * 'amount' => '10.00', - * 'currency' => 'AUD', - * 'description' => 'This is a test purchase transaction.', - * 'card' => $card, - * )); - * $response = $transaction->send(); - * if ($response->isSuccessful()) { - * echo "Purchase transaction was successful!\n"; - * $sale_id = $response->getTransactionReference(); - * echo "Transaction reference = " . $sale_id . "\n"; + * // Do a purchase transaction on the gateway + * try { + * $transaction = $gateway->purchase(array( + * 'amount' => '10.00', + * 'currency' => 'AUD', + * 'description' => 'This is a test purchase transaction.', + * 'card' => $card, + * )); + * $response = $transaction->send(); + * $data = $response->getData(); + * echo "Gateway purchase response data == " . print_r($data, true) . "\n"; + * + * if ($response->isSuccessful()) { + * echo "Purchase transaction was successful!\n"; + * } + * } catch (\Exception $e) { + * echo "Exception caught while attempting authorize.\n"; + * echo "Exception type == " . get_class($e) . "\n"; + * echo "Message == " . $e->getMessage() . "\n"; * } * * @@ -70,6 +89,135 @@ * As of January 2015 these transactions are only supported in the UK * and in the USA. * + * #### PayPal Account Payment + * + * This is for the use case where the customer intends to pay using their + * PayPal account. Note that no credit card details are provided, instead + * both a return URL and a cancel URL are required. + * + * The optimal solution here is to provide a unique return URL and cancel + * URL per transaction. That way your code will know what transaction is + * being returned or cancelled by PayPal. + * + * So step 1 is to store some transaction data somewhere on your system so + * that you have an ID when your transaction returns. How you do this of + * course depends on what framework, database layer, etc, you are using but + * for this step let's assume that you have a class set up that can save + * a transaction and return the object, and that you can retrieve the ID + * of that saved object using some call like getId() on the object. Most + * ORMs such as Doctrine ORM, Propel or Eloquent will have some methods + * that will allow you to do this or something similar. + * + * + * $transaction = MyClass::saveTransaction($some_data); + * $txn_id = $transaction->getId(); + * + * + * Step 2 is to send the purchase request. + * + * + * // Do a purchase transaction on the gateway + * try { + * $transaction = $gateway->purchase(array( + * 'amount' => '10.00', + * 'currency' => 'AUD', + * 'description' => 'This is a test purchase transaction.', + * 'returnUrl' => 'http://mysite.com/paypal/return/?txn_id=' . $txn_id, + * 'cancelUrl' => 'http://mysite.com/paypal/return/?txn_id=' . $txn_id, + * )); + * $response = $transaction->send(); + * $data = $response->getData(); + * echo "Gateway purchase response data == " . print_r($data, true) . "\n"; + * + * if ($response->isSuccessful()) { + * echo "Step 2 was successful!\n"; + * } + * + * } catch (\Exception $e) { + * echo "Exception caught while attempting purchase.\n"; + * echo "Exception type == " . get_class($e) . "\n"; + * echo "Message == " . $e->getMessage() . "\n"; + * } + * + * + * Step 3 is where your code needs to redirect the customer to the PayPal + * gateway so that the customer can sign in to their PayPal account and + * agree to authorize the payment. The response will implement an interface + * called RedirectResponseInterface from which the redirect URL can be obtained. + * + * How you do this redirect is up to your platform, code or framework at + * this point. For the below example I will assume that there is a + * function called redirectTo() which can handle it for you. + * + * + * if ($response->isRedirect()) { + * // Redirect the customer to PayPal so that they can sign in and + * // authorize the payment. + * echo "The transaction is a redirect"; + * redirectTo($response->getRedirectUrl()); + * } + * + * + * Step 4 is where the customer returns to your site. This will happen on + * either the returnUrl or the cancelUrl, that you provided in the purchase() + * call. + * + * If the cancelUrl is called then you can assume that the customer has not + * authorized the payment, therefore you can cancel the transaction. + * + * If the returnUrl is called, then you need to complete the transaction via + * a further call to PayPal. + * + * Note this example assumes that the purchase has been successful. + * + * The payer ID and the payment ID returned from the callback after the purchase + * will be passed to the return URL as GET parameters payerId and paymentId + * respectively. + * + * + * $paymentId = $_GET['paymentId']; + * $payerId = $_GET['payerId']; + * + * // Once the transaction has been approved, we need to complete it. + * $transaction = $gateway->completePurchase(array( + * 'payer_id' => $payer_id, + * 'transactionReference' => $sale_id, + * )); + * $response = $transaction->send(); + * if ($response->isSuccessful()) { + * // The customer has successfully paid. + * echo "Step 4 was successful!\n"; + * } else { + * // There was an error returned by completePurchase(). You should + * // check the error code and message from PayPal, which may be something + * // like "card declined", etc. + * } + * + * + * #### Note on Handling Error Messages + * + * PayPal account payments are a 2 step process. Firstly the customer needs to + * authorize the payment from PayPal to your application. Secondly, assuming that + * the customer does not have enough balance to pay the invoice from their PayPal + * balance, PayPal needs to transfer the funds from the customer's credit card to + * their PayPal account. This transaction is between PayPal and the customer, and + * not between the customer and you. + * + * If the second transaction fails then a call to completePurchase() will return + * an error. However this error message will be fairly generic. For privacy + * reasons, PayPal will not disclose to the merchant the full reason for the + * failure, they will only disclose this to the customer. + * + * Therefore on a failed completePurchase() call you could display an error message + * like this one: + * + * "PayPal failed to process the transaction from your card. For privacy reasons, + * PayPal are unable to disclose to us the reason for this failure. You should try + * a different payment method, a different card within PayPal, or contact PayPal + * support if you need to understand the reason for the failed transaction. PayPal + * may advise you to use a different card if the particular card is rejected + * by the card issuer." + * * @link https://developer.paypal.com/docs/api/#create-a-payment * @see RestAuthorizeRequest */ diff --git a/src/RestGateway.php b/src/RestGateway.php index ee89ff8..c202f91 100644 --- a/src/RestGateway.php +++ b/src/RestGateway.php @@ -24,6 +24,8 @@ * the Sandbox URIs. When you’re set to go live, use the live credentials assigned to * your app to generate a new access token to be used with the live URIs. * + * ### Test Mode + * * In order to use this for testing in sandbox mode you will need at least two sandbox * test accounts. One will need to be a business account, and one will need to be a * personal account with credit card details. To create these yo will need to go to @@ -46,13 +48,15 @@ * you need to do is provide the clientId and secret when you initialize the gateway, * or use the set*() calls to set them after creating the gateway object. * + * ### Credentials + * * To create production and sandbox credentials for your PayPal account: * * * Log into your PayPal account. * * Navigate to your Sandbox accounts at https://developer.paypal.com/webapps/developer/applications/accounts * to ensure that you have a valid sandbox account to use for testing. If you don't already have a sandbox * account, one can be created on this page. You will actually need 2 accounts, a personal account and a - * business account, the business account is the one you need to use for creating API applications. + * business account, the business account is the one you need to use for creating API applications. * * Check your account status on https://developer.paypal.com/webapps/developer/account/status to ensure * that it is valid for live transactions. * * Navigate to the My REST apps page: https://developer.paypal.com/webapps/developer/applications/myapps @@ -68,7 +72,9 @@ * stored per app then it pays to have one API app per website that you are using (and an * additional one for things like command line testing, etc). * - * Example: + * ### Example + * + * #### Initialize Gateway * * * // Create a gateway for the PayPal RestGateway @@ -81,7 +87,11 @@ * 'secret' => 'MyPayPalSecret', * 'testMode' => true, // Or false when you are ready for live transactions * )); + * * + * #### Direct Credit Card Payment + * + * * // Create a credit card object * // DO NOT USE THESE CARD VALUES -- substitute your own * // see the documentation in the class header. @@ -99,33 +109,30 @@ * 'billingState' => 'QLD', * )); * - * // Do an authorisation transaction on the gateway - * if ($gateway->supportsAuthorize()) { - * try { - * $transaction = $gateway->authorize(array( - * 'amount' => '10.00', - * 'currency' => 'AUD', - * 'description' => 'This is a test authorize transaction.', - * 'card' => $card, - * )); - * $response = $transaction->send(); - * $data = $response->getData(); - * echo "Gateway authorize response data == " . print_r($data, true) . "\n"; - * - * if ($response->isSuccessful()) { - * echo "Authorize transaction was successful!\n"; - * } - * } catch (\Exception $e) { - * echo "Exception caught while attempting authorize.\n"; - * echo "Exception type == " . get_class($e) . "\n"; - * echo "Message == " . $e->getMessage() . "\n"; + * // Do a purchase transaction on the gateway + * try { + * $transaction = $gateway->purchase(array( + * 'amount' => '10.00', + * 'currency' => 'AUD', + * 'description' => 'This is a test purchase transaction.', + * 'card' => $card, + * )); + * $response = $transaction->send(); + * $data = $response->getData(); + * echo "Gateway purchase response data == " . print_r($data, true) . "\n"; + * + * if ($response->isSuccessful()) { + * echo "Purchase transaction was successful!\n"; * } - * - * } else { - * echo "Gateway does not support authorize.\n"; + * } catch (\Exception $e) { + * echo "Exception caught while attempting authorize.\n"; + * echo "Exception type == " . get_class($e) . "\n"; + * echo "Message == " . $e->getMessage() . "\n"; * } * * + * ### Dashboard + * * Once you have processed some payments you can go to the PayPal sandbox site, * at https://www.sandbox.paypal.com/ and log in with the email address and password * of your PayPal sandbox business test account. You will then see the result @@ -182,7 +189,7 @@ public function getDefaultParameters() /** * Get OAuth 2.0 client ID for the access token. - * + * * Get an access token by using the OAuth 2.0 client_credentials * token grant type with your clientId:secret as your Basic Auth * credentials. @@ -196,7 +203,7 @@ public function getClientId() /** * Set OAuth 2.0 client ID for the access token. - * + * * Get an access token by using the OAuth 2.0 client_credentials * token grant type with your clientId:secret as your Basic Auth * credentials. @@ -211,7 +218,7 @@ public function setClientId($value) /** * Get OAuth 2.0 secret for the access token. - * + * * Get an access token by using the OAuth 2.0 client_credentials * token grant type with your clientId:secret as your Basic Auth * credentials. @@ -225,7 +232,7 @@ public function getSecret() /** * Set OAuth 2.0 secret for the access token. - * + * * Get an access token by using the OAuth 2.0 client_credentials * token grant type with your clientId:secret as your Basic Auth * credentials. @@ -272,7 +279,7 @@ public function createToken() /** * Set OAuth 2.0 access token. - * + * * @param string $value * @return RestGateway provides a fluent interface */ @@ -283,7 +290,7 @@ public function setToken($value) /** * Get OAuth 2.0 access token expiry time. - * + * * @return integer */ public function getTokenExpires() @@ -293,7 +300,7 @@ public function getTokenExpires() /** * Set OAuth 2.0 access token expiry time. - * + * * @param integer $value * @return RestGateway provides a fluent interface */ @@ -503,7 +510,7 @@ public function refund(array $parameters = array()) * with PayPal instead of storing them on your own server. After storing * a credit card, you can then pass the credit card id instead of the * related credit card details to complete a payment. - * + * * @link https://developer.paypal.com/docs/api/#store-a-credit-card * @param array $parameters * @return \Omnipay\PayPal\Message\RestCreateCardRequest @@ -519,7 +526,7 @@ public function createCard(array $parameters = array()) * Updating a card in the vault is no longer supported -- see * http://stackoverflow.com/questions/20858910/paypal-rest-api-update-a-stored-credit-card * Therefore the only way to update a card is to remove it using deleteCard and - * then re-add it using createCard. + * then re-add it using createCard. * * @link https://developer.paypal.com/docs/api/#delete-a-stored-credit-card * @param array $parameters