I know there are a few questions regarding PayPal Integration but I'm trying to implement PayPal Express Checkout with Smart Buttons and REST API and no success.
What I want to do is:
Create a Payment Authorization (with payidand orderid)
Send this payid to the client (javascript) to be approved.
Redirect after payment to a confirmation page.
I have already created a Payment Authorization with the code bellow:
<?php
// 1. Autoload the SDK Package. This will include all the files and classes to your autoloader
// Used for composer based installation
require __DIR__ . '/PayPal-PHP-SDK/autoload.php';
// Use below for direct download installation
// require __DIR__ . '/PayPal-PHP-SDK/autoload.php';
// After Step 1
$apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential(
'client id', // ClientID
'cliente secret' // ClientSecret
)
);
// After Step 2
$payer = new \PayPal\Api\Payer();
$payer->setPaymentMethod('paypal');
$amount = new \PayPal\Api\Amount();
$amount->setTotal('1.00');
$amount->setCurrency('USD');
$transaction = new \PayPal\Api\Transaction();
$transaction->setAmount($amount);
$redirectUrls = new \PayPal\Api\RedirectUrls();
$redirectUrls->setReturnUrl("https://example.com/your_redirect_url.html")
->setCancelUrl("https://example.com/your_cancel_url.html");
$payment = new \PayPal\Api\Payment();
$payment->setIntent('sale')
->setPayer($payer)
->setTransactions(array($transaction))
->setRedirectUrls($redirectUrls);
// After Step 3
try {
$payment->create($apiContext);
echo $payment;
echo "\n\nRedirect user to approval_url: " . $payment->getApprovalLink() . "\n";
echo $data= json_encode($payment->id, JSON_PRETTY_PRINT), "\n";
echo "</br>";echo "</br>";
echo $data= $payment->id;
}
catch (\PayPal\Exception\PayPalConnectionException $ex) {
// This will print the detailed information on the exception.
//REALLY HELPFUL FOR DEBUGGING
echo json_encode($ex->getData()->id, JSON_PRETTY_PRINT), "\n";
echo "</br>";echo "</br>";
echo $ex->getData()->id;
}
?>
My setup is as following (Please, correct if it's wrong):
User chooses the item and submits the form.
User is redirected to a new page with a new form and then fills the form with his name and other personal informations and then submits the form to be saved in the database and generate the Payment Authorization.
User should be redirected to a final page with Smart Buttons to complete the payment.
User should be redirected to a confirmation page, confirming his payment was successfully made.
The problem is that I'm stuck in the step 2 because once I generate the Payment Authorization, I don't know how to pass this id (and other required parameters) to the client, in this new page that is supposed to show the Smart Payment Buttons to complete the transaction.
I'm following along with the tutorial in PayPal documentation but I'm not able to understand.
The JavaScript makes calls to my server to get the payid, it works, but it generates a new payid and a new Payment Order, i want to use the one that was previously created when the user submitted the form and then, somehow, pass it to the final page with the Smart Buttons to complete the transaction and redirect to a confirmation page.
My Javascript:
<script>
paypal.Button.render({
onApprove: function(data) {
return fetch('/my-server/get-paypal-transaction', {
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
orderID: data.orderID
})
}).then(function(res) {
return res.json();
}).then(function(details) {
alert('Transaction approved by ' + details.payer_given_name);
}, '#paypal-button');
</script>
The problem is that it generates a new orderID, a new transaction, and I want to retrieve the transaction that was generated when the user submitted the form in the step 2 but I don't know what I should do.
Ultimately what I need is:
Get the Payment Authorization and pass it to the Client (final page with the buttons)
Redirect the users after payment complete.
You are looking for this front-end: https://developer.paypal.com/demo/checkout/#/pattern/server
For your backend, you should use the latest v2/orders SDK: https://github.com/paypal/Checkout-PHP-SDK
(Your v1/payments backend will work, but that SDK is deprecated and there is no reason to use it for a new integration)
Related
I have created a webhook using some samples. I am able to get leads information when using webhooks Test but not able to get the leads info using a Test form:
Steps I have followed:
1. Created a Facebook APP.
2. Added Facebook Login and leads_retrieval permission.
3. Subscribed my page
4. Created endpoints and Subscribed my App for leadgen
webhoook.php
<?php
// facebook variables
$challenge = isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : '';
$verify_token = isset($_REQUEST['hub_verify_token']) ? $_REQUEST['hub_verify_token'] : '';
$fb_access_token = "myaccesstoken";
// this is used to subscribe to facebook webhook
if ($verify_token === "abc123")
{
echo $challenge;
}
// Process retrieved data from facebook webhook
$data = json_decode(file_get_contents("php://input"),true);
$leadgen_id = $data['entry'][0]['changes'][0]['value']['leadgen_id']; // extract leadgen ID
error_log(print_r($leadgen_id, true));
?>
Output while testing from the App Webhook Dashboard:
[27-Feb-2019 09:09:50 Etc/GMT] 444444444444
But when I created a Test Form and trying from https://developers.facebook.com/tools/lead-ads-testing then it's not firing any event.
Output: failure 102 Server failure
My Test from has: Full name, email, Mobile No, State and city values
I have a Progressive Web App built with Angular 4.
My Problem is the Fb login dialog does not close automatically when used from the home screen app. It works perfectly fine when opened in chrome browser but when i use it from installed home screen app the dialog window opens asks for permissions, after all permission is given the dialog goes blank and does not close or redirects back to the app.
It seems like if i change the "display" in manifest.json to "browser" it works but does not work when "display" is in "standalone".
I have searched all over but no success.
Thanks
When your app is installed as a progressive web app, the Facebook login popup and the parent window (your app) can't communicate the way they do in a desktop environment.
You'll face this problem in other scenarios as well, e.g. when your app is launched using in-app browsers like Instagram's or Facebook's.
You can implement a server-based flow as suggested by another answer. You can also implement a custom redirect flow on the client side.
A custom redirect flow works without popups. When your user clicks a "Login" button, he/she is instead redirected to a Facebook login screen. After logging in, the user is directed back to your app using a URL that contains everything you need to verify the success or failure of the authentication.
How to create a custom redirect flow is described in the Facebook SDK documentation, under "Manually Building a Login Flow":
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
The idea is as follows:
You direct your users to the Facebook login dialog (not the popup launched by FB.login()), e.g. when they click a button:
https://www.facebook.com/v2.11/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&response_type=token
&state={state-param}
If the user successfully grants your app the necessary permissions, he/she is redirected back to your app (the location is determined by {redirect-url}):
{redirect-uri}?code=<facebook-code>&state={state}#_=_
Then you app needs to figure out whether the login was successful or not. There are two ways to do this:
A) Read the query string of the current URL (see the code=<code> part -- this can be used to retrieve additional info about your user, or it can be sent to your backend server).
B) Use the Facebook SDK do retrieve the login status using FB.getLoginStatus(yourCallback)
If you're already using the SDK and FB.login(yourCallback), you can add yourCallback to FB.getLoginStatus as well. You can also support both a popup flow and a redirect flow depending on the user's device.
I suggest reading through the documentation entry I posted above for further information and options.
I kind of figured out a way to do this for FB. Used FB PHP SDK to generate a login url and opened the url on a child window and the whole login dialog & permissions thing happens and it redirects to my redirect_url where I pass the necessary data to parent window using window.opener.postMessage.
My redirect_url page is setup like this:
<?php
if ( ! session_id()) {
session_start();
}
require_once "vendor/autoload.php";
$_SESSION['FBRLH_state'] = $_GET['state'];
$fb = new Facebook\Facebook([
'app_id' => 'FBID', // Replace {app-id} with your app id
'app_secret' => 'FBSECRET',
'default_graph_version' => 'v2.2',
]);
$helper = $fb->getRedirectLoginHelper();
try {
$accessToken = $helper->getAccessToken();
} catch (Facebook\Exceptions\FacebookResponseException $e) {
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch (Facebook\Exceptions\FacebookSDKException $e) {
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
if ( ! isset($accessToken)) {
if ($helper->getError()) {
header('HTTP/1.0 401 Unauthorized');
echo "Error: " . $helper->getError() . "\n";
echo "Error Code: " . $helper->getErrorCode() . "\n";
echo "Error Reason: " . $helper->getErrorReason() . "\n";
echo "Error Description: " . $helper->getErrorDescription() . "\n";
} else {
header('HTTP/1.0 400 Bad Request');
echo 'Bad request';
}
exit;
}
$oAuth2Client = $fb->getOAuth2Client();
$tokenMetadata = $oAuth2Client->debugToken($accessToken);
$tokenMetadata->validateAppId('FBID'); // Replace {app-id} with your app id
$tokenMetadata->validateExpiration();
if ( ! $accessToken->isLongLived()) {
try {
$accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
} catch (Facebook\Exceptions\FacebookSDKException $e) {
echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
exit;
}}
$_SESSION['fb_access_token'] = (string)$accessToken;
$tk = $_SESSION['fb_access_token'];
?>
<?= $tk;?>
<script type="text/javascript">
window.opener.postMessage({token: '<?= $tk;?>'}, '*');
window.close();
</script>
In the parent window I have an eventListener which is listening to the postMessage using window.addEventListener("message", receiveMessage, false);and the receiveMessage function handles all the data as required. So any web app using standalone mode should be able to get data from child window.
Window postmessage can be used to pass data between cross-origins. More details on postMessage are here: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
I have scoured the docs and this tutorial about 100 times but can't figure out how to go through the payment process using a PayPal account as opposed to a credit card. I have gotten the credit card payment to go through just fine.
In the aforementioned tutorial, it is stated that I am supposed to expect a JSON response from the server after making an OAuth credential:
$sdkConfig = array(
"mode" => "sandbox"
);
$cred = new OAuthTokenCredential("clientID","clientSecret", $sdkConfig);
I get absolutely no server response despite geting a '200 OK' status from the server.
Initially I had my code set up like a bunch of other tutorials:
$apiContext = new ApiContext(
new OAuthTokenCredential(
'clientID', // ClientID
'clientSecret' // ClientSecret
)
);
$payer = new Payer();
$payer->setPaymentMethod('paypal');
$item1 = new Item();
$item1->setName("Donation squares.");
$item1->setCurrency('USD');
$item1->setQuantity(1);
$item1->setPrice(1);
$itemList = new ItemList();
$itemList->setItems(array($item1));
$amountDetails = new Details();
$amountDetails->setSubtotal('7.41');
$amountDetails->setTax('0.03');
$amountDetails->setShipping('0.03');
$amount = new Amount();
$amount->setCurrency('USD');
$amount->setTotal('7.47');
$amount->setDetails($amountDetails);
$transaction = new Transaction();
$transaction->setAmount($amount);
$transaction->setDescription('This is the payment transaction description.');
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("https://devtools-paypal.com/guide/pay_paypal/php?success=true");
$redirectUrls->setCancelUrl("https://devtools-paypal.com/guide/pay_paypal/php?cancel=true");
$payment = new Payment();
$payment->setIntent('sale');
$payment->setPayer($payer);
$payment->setRedirectUrls($redirectUrls);
$payment->setTransactions(array($transaction));
try{
$payment->create($apiContext);
} catch(Exception $e){
echo $e
exit(1);
}
None of this works either - no response from the server whatsoever.
ANSWER / COMMENT
You're not supposed to be looking for a JSON response after all. If the payment is successfully created, an approval URL should be generated by running
$payment->getApprovalLink();
The user then follows this link to finalize his/her payment.
You might be interested in following a very simple instruction here at PayPal-PHP-SDK, that explains how to make calls using PayPal PHP SDK. I know you have already gone through that, and are looking for how to create a payment using PayPal.
I am not sure you are aware of this, but PayPal-PHP-SDK comes along with a lot of samples, that you could run by just one simple command (if you have PHP 5.4 or higher). One of the first sample have the instructions and code to make PayPal Call.
There are two steps involved in that.
Create a Payment. Receive a approval_url link to be used to ask the user to complete Paypal flow over any browser.
Once the user accepts the payment on paypal website, it will be redirected back to your website, where you execute the payment.
Both the code samples are provided here and here.
Let me know if this helps, and you have any more questions. I would be more than happy to help.
I am using virtuemart in joomla for ecommerce purpose. It's working fine. But after checkout from cart it redirect to paypal ( or other payment system). After completion of payment process, paypal again redirects to my website. It's working all stuff smoothly. But problem is that how to know that payment process is complete successfully or not from my website? Is virtuemart automatic does this or not ? if yes then, which file is responsible for this ?
It's not automatic, but it's also not hard (aside from VM's terrible documentation), here's a skeleton of the plugin you want to write:
<?php
defined('_JEXEC') or die('Restricted access');
if (!class_exists('vmCustomPlugin')){
require(JPATH_VM_PLUGINS . '/vmcustomplugin.php');
}
class plgVmcustomAfterOrderConfirmedHook extends vmCustomPlugin {
function plgVmConfirmedOrder($cart, $order){
$db = JFactory::getDBO();
$db->setQuery($db->getQuery(true)
->select('order_status')
->from('#__virtuemart_orders')
->where('virtuemart_order_id = '.intval($order['details']['BT']->virtuemart_order_id)));
if($db->loadResult() === 'C'){
blah();
}
}
}
?>
I'm using the javascript SDK to fire the send method of fb.ui. It works if I'm logged in as myself and send the messages to other developers on my team. When I log on as a test user and send to another test user, there is no error but the receiver never gets the message.
Code below shows click event from my button:
$(".invite_fb_friends").click(function() {
<?php
$subject = __("Please check out Volved", "volved", "volved");
if (isset($current_user->volved_cause)) {
$p = get_post($current_user->volved_cause);
$invite_id = get_user_personal_invite();
$description = sprintf(__("Follow this link and join me in supporting %s, or a cause of your choice!"),
$p->post_title);
$link = site_url("/cause/". $p->post_name . "/?invite_id=" . $invite_id);
$picture = get_bloginfo('template_directory'). '/images/cause_images/' . $p->post_name . '/logo.jpg';
} else {
//No cause chosen
$description = __("If you follow this link, you'll learn about Volved. If you like, sign up and start making a difference.");
$link = site_url("/");
$picture = get_bloginfo('template_directory') . '/images/logo64.png';
}
//call below documented at: https://developers.facebook.com/docs/reference/dialogs/send/
?>
res = FB.ui({
method: 'send',
name: '<?php echo $subject; ?>',
link: '<?php echo $link; ?>',
//picture: '<?php echo $picture; ?>', //Does not seem to work with valid URL. HTML shows URL but no pic displayed. Leaving blank shows picture of sender
//redirect_uri: filling this in creates an error on facebook
description: '<?php echo $description; ?>'
});
});
Test users can only send messages to other test users. If your other user is a real user, your own account for example, it will not send.
From Facebook:
https://developers.facebook.com/docs/test_users/
Limitations
We ensure that test users are exempt from Facebook spam or fake
account detection systems to ensure that you can test your app without
worrying about getting disabled.
Also, to ensure that using test user accounts to test various
scenarios doesn't end up unintentionally creating spam, we enforce
certain limitations on what test users can do.
Test users can interact with other test users only and not with real
users on site. Test users cannot fan a public Page or create public
content on them like writing on a Page's wall. A Test user can however
view and interact with the app tab on the Page if they are associated
with that app. They can be accessed and used by any developer of the
associated app. They only have test privileges on the associated app.
This implies that they can use the app in live mode or sandbox mode
but cannot edit any technical settings or access insights for that
app. A test user is always a test user and cannot be converted to a
normal user account.