Issue
I have 3 files (simple script) to make a payment with PayPal (v1 API) :
1: index.htm (start payment):
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- Replace "test" with your own sandbox Business account app client ID -->
<script src="https://www.paypal.com/sdk/js?client-id=test&disable-funding=credit,card"></script>
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
// Sets up the transaction when a payment button is clicked
style: {
shape: 'rect',
color: 'gold',
layout: 'horizontal',
label: 'paypal',
},
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [{
amount: {
currency_code :'USD',
value: '77.44' // Can also reference a variable or function
}
}]
});
},
// Finalize the transaction after payer approval
onApprove: (data, actions) => {
return actions.order.capture().then(function(orderData) {
// Successful capture!
window.location = "paypal-verify.php?id="+data.orderID;
});
}
}).render('#paypal-button-container');
</script>
</body>
</html>
2: paypal-client.php (connect to api):
<?php
use PayPalCheckoutSdk\Core\PayPalHttpClient;
//use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
class PayPalClient {
Public static function client()
{
return new PayPalHttpClient(self::environment());
}
public static function environment()
{
$clientId = getenv("CLIENT_ID") ? : "XXXX";
$clientSecret = getenv("CLIENT_SECRET") ? : "YYYY";
//return new SandboxEnvironment($clientId,$clientSecret);
return new ProductionEnvironment($clientId,$clientSecret);
}
}
3: paypal-verify.php (to verify payment):
<?php
require __DIR__.'/vendor/autoload.php';
require __DIR__.'/paypal-client.php';
use PayPalCheckoutSdk\Orders\OrdersGetRequest;
class GetOrder
{
public function verify($orderId)
{
$reply = new stdClass();
$reply->verify = false;
try
{
$client = PayPalClient::client();
$response = $client -> execute (new OrdersGetRequest($orderId));
$statusCode = $response-> statusCode;
$transactionId = $response->result->purchase_units[0]->payments->captures[0]-> id;
//$email = $response->result-> payer->email_address;
//$name = $response->result-> purchase_units[0]->shipping->name->full_name;
//$amount = $response->result-> purchase_units[0]->amount->value;
if ($statusCode == 200 || $statusCode == 201) {
$reply->verify = true;
$reply->ref= $transactionId;
} else {
$reply->ref= "error:" .$statusCode;
}
}
catch (\PayPalHttp\HttpException $e)
{
//echo $e->getMessage();
$reply->ref = "error in verifying transaction!";
}
catch (\PayPal\Exception\PayPalConnectionException $e)
{
//echo $e->getMessage();
$reply->ref = "Error in verifying transaction!";
}
catch (\PayPalHttp\IOException $e)
{
//echo $e->getMessage();
$reply->ref = "Error in connecting paypal server!";
}
return $reply;
}
}
$id = empty($_GET['id']) ? "" : $_GET['id'];
if (!count(debug_backtrace()))
{
$order = new GetOrder();
$reply = $order->verify($id);
var_dump($reply);
}
Apparently the code is working but the question :
My method to check that payment settled or not (by comparing statusCode with 200 or 201) is enough and standard?
Any other suggestion about whole code would be appreciated. With the best.
Solution
To be sure, don't use the actions.order.create / .capture client-side functions. These are for simpler use cases. Any number of problems could prevent your system from recording a transaction after the fact.
Instead, use the v2/checkout/orders API and make two routes (url paths) on your server, one for 'Create Order' and one for 'Capture Order'. You can use the (recently deprecated) Checkout-PHP-SDK for the routes' API calls to PayPal, which I see in your question -- or your own HTTPS implementation of first getting an access token and then doing the call. Both of these routes should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should verify the amount was correct and store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id
, which is the PayPal transaction ID) and perform any necessary business logic (such as reserving product or sending an email) immediately before forwarding return JSON to the frontend caller. In the event of an error forward the JSON details of it as well, since the frontend must handle such cases.
Pair those 2 routes with this frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server . (If you need to send any additional data from the client to the server, such as an items array or selected options, add a body
parameter to the fetch with a value that is a JSON string or object)
Answered By - Preston PHX Answer Checked By - Mildred Charles (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.