I'm using the PayPal API in PHP to create transactions, both with a credit card and via PayPal itself. Additionally, I need to be able to refund these transactions. The code I'm using, which is mostly straight from the PayPal API sample, works fine for credit card transactions, but it fails for PayPal transactions. Specifically, I'm attempting to drill down through the Payment object and pull out the ID of that Sale. Payment objects made via credit cards contain a RelatedResources object, which in turn contains the Sale object, with the ID, but Payment objects made via PayPal don't seem to contain them. So, my question is, how can I retrieve the Sale ID from a payment made via PayPal?
Here's how I create a payment with a stored credit card:
$creditCardToken = new CreditCardToken();
$creditCardToken->setCreditCardId('CARD-2WG5320481993380UKI5FSFI');
// ### FundingInstrument
// A resource representing a Payer's funding instrument.
// For stored credit card payments, set the CreditCardToken
// field on this object.
$fi = new FundingInstrument();
$fi->setCreditCardToken($creditCardToken);
// ### Payer
// A resource representing a Payer that funds a payment
// For stored credit card payments, set payment method
// to 'credit_card'.
$payer = new Payer();
$payer->setPaymentMethod("credit_card")
->setFundingInstruments(array($fi));
// ### Amount
// Lets you specify a payment amount.
// You can also specify additional details
// such as shipping, tax.
$amount = new Amount();
$amount->setCurrency("USD")
->setTotal('1.00');
// ### 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");
// ### Payment
// A Payment Resource; create one using
// the above types and intent set to 'sale'
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setTransactions(array($transaction));
// ###Create 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.
try {
$payment->create($apiContext);
} catch (PayPal\Exception\PPConnectionException $ex) {
error_log($ex->getMessage());
error_log(print_r($ex->getData(), true));
}
By contrast, here's how I make a PayPal payment. It's a 2-step process. First the user's directed to PayPal's site, and then, when they return to my site, the payment's processed.
Part 1:
$payer = new Payer();
$payer->setPaymentMethod("paypal");
$amount = new Amount();
$amount->setCurrency("USD")
->setTotal($userInfo['amount']);
$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 = 'http://example.com';
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("$baseUrl/?success=true")
->setCancelUrl("$baseUrl/?success=false");
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions(array($transaction));
try {
$payment->create($apiContext);
} catch (PayPal\Exception\PPConnectionException $ex) {
error_log($ex->getMessage());
error_log(print_r($ex->getData(), true));
return;
}
// ### Get redirect url
// The API response provides the url that you must redirect
// the buyer to. Retrieve the url from the $payment->getLinks()
// method
foreach($payment->getLinks() as $link) {
if($link->getRel() == 'approval_url') {
$redirectUrl = $link->getHref();
break;
}
}
// ### Redirect buyer to PayPal website
// Save payment id so that you can 'complete' the payment
// once the buyer approves the payment and is redirected
// bacl to your website.
//
// It is not really a great idea to store the payment id
// in the session. In a real world app, you may want to
// store the payment id in a database.
$_SESSION['paymentId'] = $payment->getId();
if(isset($redirectUrl)) {
$response->redirectUrl = $redirectUrl;
}
return $response;
And here's part 2, when the user's redirected to my site with a 'success' message:
$payment = Payment::get($lineitem->paypal_payment_ID, $apiContext);
// PaymentExecution object includes information necessary
// to execute a PayPal account payment.
// The payer_id is added to the request query parameters
// when the user is redirected from paypal back to your site
$execution = new PaymentExecution();
$execution->setPayer_id($_GET['PayerID']);
//Execute the payment
// (See bootstrap.php for more on `ApiContext`)
$payment->execute($execution, $apiContext);
And here's how I refund a transaction. The Sample in the API doesn't discuss how to retrieve a Sale ID, so I drill down through the objects. The Payments made via PayPal don't have a RelatedResources object, so it fails:
try {
$payment = Payment::get('PAY-8TB50937RV8840649KI6N33Y', $apiContext);
$transactions = $payment->getTransactions();
$resources = $transactions[0]->getRelatedResources();//This DOESN'T work for PayPal transactions.
$sale = $resources[0]->getSale();
$saleID = $sale->getId();
// ### Refund amount
// Includes both the refunded amount (to Payer)
// and refunded fee (to Payee). Use the $amt->details
// field to mention fees refund details.
$amt = new Amount();
$amt->setCurrency('USD')
->setTotal($lineitem->cost);
// ### Refund object
$refund = new Refund();
$refund->setAmount($amt);
// ###Sale
// A sale transaction.
// Create a Sale object with the
// given sale transaction id.
$sale = new Sale();
$sale->setId($saleID);
try {
// Refund the sale
// (See bootstrap.php for more on `ApiContext`)
$sale->refund($refund, $apiContext);
} catch (PayPal\Exception\PPConnectionException $ex) {
error_log($ex->getMessage());
error_log(print_r($ex->getData(), true));
return;
}
} catch (PayPal\Exception\PPConnectionException $ex) {
error_log($ex->getMessage());
error_log(print_r($ex->getData(), true));
return;
}
Any thoughts on how to retrieve the Sale ID? Thanks!