PayPal Smart Button server side implementation - Problems with capturing transaction - PHP - php

I've been trying to finish my server side implementation of the PayPal Smart Button and got stuck with capturing the transaction. I'm using a Sandbox account. I'm not sure if the problem is the order ID.
The response I get when trying to capture a transaction:
Fatal error: Uncaught PayPalHttp\HttpException:
{"name":"RESOURCE_NOT_FOUND",
"details[{"field":"order_id",
"value":"$orderId",
"location":"path",
"issue":"INVALID_RESOURCE_ID",
"description":"Specified resource ID does not exist. Please check the resource ID and try again."}],
"message":"The specified resource does not exist.",
"debug_id":"df5cdbddfc1ea",
"links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-INVALID_RESOURCE_ID",
"rel":"information_link","method":"GET"}]} in /usr/local/ampps/www/shop-files/vendor/paypal/paypalhttp/lib/PayPalHttp/HttpClient.php:215
Stack trace: #0 /usr/local/ampps/www/shop-files/vendor/paypal/paypalhttp/lib/PayPalHttp/HttpClient.php(100): PayPalHttp\HttpClient->parseResponse(Object(PayPalHttp\Curl))
#1 /usr/local/ampps/www/shop-files/capture-transaction.php(29): PayPalHttp\HttpClient->execute(Object(PayPalCheckoutSdk\Orders\OrdersCaptureRequest))
#2 /usr/local/ampps/www/shop-files/capture-transaction.php(62): Sample\CaptureIntentExamples\CaptureOrder::captureOrder('$orderId', in /usr/local/ampps/www/shop-files/vendor/paypal/paypalhttp/lib/PayPalHttp/HttpClient.php on line 215
The response I get when creating a transaction:
{
"id": "1XB529992P492602W",
"intent": "CAPTURE",
"status": "CREATED",
"purchase_units": [
{
"reference_id": "default",
"amount": {
"currency_code": "GBP",
"value": "12.00"
},
"payee": {
"email_address": "sb-lxq8v1263761#business.example.com",
"merchant_id": "SUHPR7WSYJPJQ"
}
}
],
"create_time": "2020-10-14T08:36:00Z",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/1XB529992P492602W",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.sandbox.paypal.com/checkoutnow?token=1XB529992P492602W",
"rel": "approve",
"method": "GET"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/1XB529992P492602W",
"rel": "update",
"method": "PATCH"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/1XB529992P492602W/capture",
"rel": "capture",
"method": "POST"
}
]
}
My php code for creating a transaction:
<?php
namespace Sample\CaptureIntentExamples;
session_start();
require __DIR__ . '/vendor/autoload.php';
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
require 'paypal-client.php';
class CreateOrder {
public static function createOrder() {
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = self::buildRequestBody();
$client = PayPalClient::client();
$response = $client->execute($request);
echo json_encode($response->result, JSON_PRETTY_PRINT);
return $response;
}
private static function buildRequestBody() {
return array(
'intent'=>'CAPTURE',
'application_context'=>
array(
'return_url'=>'https://localhost/basket.php',
'cancel_url'=>'https://localhost/basket.php'
),
'purchase_units'=>
array(
0=>
array(
'amount'=>
array(
'currency_code'=>'GBP',
'value'=>$_SESSION['total']
)
)
)
);
}
}
if (!count(debug_backtrace()))
{
CreateOrder::createOrder(true);
}
?>
Code for capturing a transaction:
<?php
namespace Sample\CaptureIntentExamples;
require __DIR__ . '/vendor/autoload.php';
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
require 'paypal-client.php';
class CaptureOrder
{
public static function captureOrder($orderId)
{
$request = new OrdersCaptureRequest($orderId);
$client = PayPalClient::client();
$response = $client->execute($request);
echo json_encode($response->result, JSON_PRETTY_PRINT);
return $response;
}
}
if (!count(debug_backtrace()))
{
CaptureOrder::captureOrder('$orderId', true);
}
?>
JavaScript:
createOrder: function(data) {
return fetch('/shop-files/create-order.php', {
method: 'post',
}).then(function(res) {
return res.json();
}).then(function(orderData) {
return orderData.id;
});
},
onShippingChange: function(data, actions) {
if (data.shipping_address.country_code !== "GB") {
return actions.reject();
}
return actions.resolve();
},
onApprove: function(data) {
return fetch('/shop-files/capture-transaction.php', {
method: 'post',
headers: {
'content-type': 'application/json'
},
}).then(function(res) {
return res.json();
}).then(function(orderData) {
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart();
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
if (errorDetail.description) msg += '\n\n' + errorDetail.description;
if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
return alert(msg);
}
alert('Transaction completed by ' + orderData.payer.name.given_name);
});
}
}).render('#paypal-button-container');

This is your problem line:
CaptureOrder::captureOrder('$orderId', true);
You are literally sending the text string inside the single quotes: '$orderId' to PayPal. The $ and those 7 letters are going to PayPal. You are not sending the contents of your $orderId variable.
Get rid of your string quotes:
CaptureOrder::captureOrder($orderId, true);
By the way, a detail about PHP (and incidentally, shell languages like bash) you may not be aware of:
Note: Unlike the double-quoted and heredoc syntaxes, variables and escape sequences for special characters will not be expanded when they occur in single quoted strings.
ref: https://www.php.net/manual/en/language.types.string.php#language.types.string.parsing
Basically, double quotes and single quotes behave differently in this respect.

This is what I added to my code for capturing a transaction to get the order's ID, right below require 'paypal-client.php';:
// Get JSON row data from the request
$json = file_get_contents('php://input');
// Convert JSON string into array
$data = json_decode($json, true);
// Get the value of the key 'orderID'
$orderId = $data['orderID'];
I'm not sure if the comments explain exactly what is happening, so any correction would be most welcome.
Also the JavaScript code is a bit different with this:
body: JSON.stringify({
orderID: data.orderID
})
added just below
headers: {
'content-type': 'application/json'
},
It's working now. Many thanks Preston PHX for pointing me in the right direction again.

Related

How to send values from payment page using the server implementation(PHP) of Paypal Checkout?

I am trying to implement the server integration of PayPal Checkout, as per this page, and setting up a transaction as per this page.
As far as I understand from other posts the "best" way is by creating 2 routes, using the createOrder and onApprove methods for creating and validating the executed orders.
I have successfully installed the Checkout PHP SDK and I'm able to launch a transaction using this code:
Client side javascript (checkoutpage.php):
paypal.Buttons({
// Call your server to set up the transaction
createOrder: function(data, actions) {
return fetch('createorder.php', {
method: 'post'
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// console.log(orderData);
return orderData.id;
});
},
//onApprove function below left out for clarity purposes
onApprove: function(data) {}
}).render('#paypal-button-container');
and the server side PHP code (createorder.php):
<?php
namespace Sample\CaptureIntentExamples;
require __DIR__ . '/route/to/paypal/autoload.php';
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
class CreateOrder
{
public static function createOrder($debug=false)
{
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = self::buildRequestBody();
$client = PayPalClient::client();
$response = $client->execute($request);
if ($debug)
{
echo json_encode($response->result, JSON_PRETTY_PRINT);
}
return $response;
}
private static function buildRequestBody()
{
return array(
'intent' => 'CAPTURE',
'application_context' =>
array(
'return_url' => 'https://example.com/return',
'cancel_url' => 'https://example.com/cancel'
),
'purchase_units' =>
array(
0 =>
array(
'amount' =>
array(
'currency_code' => 'USD',
'value' => '2.00'
)
)
)
);
}
}
if (!count(debug_backtrace()))
{
CreateOrder::createOrder(true);
}
?>
Up to this point the transaction is launched with the data located in the purchase_units array in the createorder.php page. My question is how can I send those values from the checkoutpage.php to the createorder.php page, while maintaining the server side PHP implementation? as opposed to setting it up 100% client side like this:
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '88.44'
}
}]
});
},
The reason is that the values such as price, number of items, shipping charges, etc can be changed dynamically with JS in the checkout page, while in other instances a static DB value is used.
Thanks in advance
I finally found the solution:
Client side:
createOrder: function(data, actions) {
return fetch('createorder.php', {
method: 'post',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "100.00"
}
}
]
})
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// console.log(orderData);
return orderData.id;
});
},
and server side PHP:
<?php
namespace Sample\CaptureIntentExamples;
require __DIR__ . '/route/to/paypal/autoload.php';
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
class CreateOrder
{
public static function createOrder($debug=false)
{
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = file_get_contents('php://input');
$client = PayPalClient::client();
$response = $client->execute($request);
if ($debug)
{
echo json_encode($response->result, JSON_PRETTY_PRINT);
}
return $response;
}
}
if (!count(debug_backtrace()))
{
CreateOrder::createOrder(true);
}
?>

Getting error 404 when post data from local storage

I want to retrieve data from local storage and save it to the database. But when I'm trying to post, It gives an error 404. I know the file exist because when I remove this line :
formData.append('data',array);
my post is work. However, It works on localhost not on live server.
Whats wrong with this code.
Data from localstorage :
{
"mylist":"name of list",
"list": {
"category":[ {
"name":"Category 1",
"items":[ {
"name": "Category item list 1, "amount": "0"
}
]
}
,
{
"name":"Category 2",
"items":[ {
"name": "Category item list 2, "amount": "0"
}
]
}
]
}
}
React js trigger post :
function savepackList(){
const array = localStorage.getItem('list');
let formData = new FormData();
formData.append('type','savelist');
formData.append('data',array); //removing this it does not give a 404 error
axios.post('/request.php',formData)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});return;
}
PHP code :
if($_POST['type']=='savelist'){
$obj = json_decode($_POST['data'],true);
echo json_encode($obj);
}

using php, how to fetch a specific data from dialogflow fulfillment JSON request and store the data into a php variable

Using php, how can I fetch specific data from dialogflow fulfillment JSON request and store the data into a php variable?
Here is the JSON response I 'm getting from my dialogflow agent
{
"responseId": "e9106589-2a41-47c4-bdde-8f3cee8f40da",
"queryResult": {
"queryText": "switch on cfl",
"action": "input.switchoncfl",
"parameters": {
"makeRequest": "cfl_on"
},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"platform": "ACTIONS_ON_GOOGLE",
"simpleResponses": {
"simpleResponses": [
{
"textToSpeech": "Sure. Turning CFL on... Anything else can I help you with?",
"displayText": "Sure. Turning CFL on..."
}
]
}
}
],
"intent": {
"name": "projects/smarthome-cf277/agent/intents/5be27f38-105d-4854-b62d-ec3a6de80cc7",
"displayName": "1.1-Switch_on_CFL"
},
"intentDetectionConfidence": 1,
"languageCode": "en"
},
"originalDetectIntentRequest": {
"payload": {}
},
"session": "projects/smarthome-cf277/agent/sessions/ca0261aa-913f-96f1-b5aa-7755637d5ab7"
}
And here is my php code
<?php
header("Content-Type: application/json");
ob_start();
$content = json_decode(file_get_contents('php://input'),true);
$action = $content['parameters']['makeRequest'];
ob_end_clean();
?>
I want to store cfl_on value to $action variable. How can I do that? this php code does not work.
You just missed out the "queryResult" layer of the object.
$action = $content['queryResult']['parameters']['makeRequest'];

Request object properties are empty, yet request is made

Creating a bolt extension and trying to access request variables. I have set up an endpoint GET /api/session, which for now should just return the request:
public function initialize()
{
$this->app->get("/api/session", array($this, 'getSession'))
->bind('getSession');
}
public function getSession(Request $request)
{
$response = $this->app->json(array('request' => $request));
return $response;
}
But the response is:
"request": {
"attributes": { },
"request": { },
"query": { },
"server": { },
"files": { },
"cookies": { },
"headers": { }
}
There were headers sent, and I've tested it with queries too, but nothing is returned in the response. How do I get the full response? Full code is available at: https://github.com/babaggeii/bolt-extension-restapi

JavaScript returns "is not a function" error yet the method is listed in response in Firebug

I am getting the following error in Firebug when loading a web page:
redirect.processBrowser is not a function
[Break On This Error]
url = redirect.processBrowser(JSON.stringify(browserInfo));
The response as seen in Firebug is as follows:
{"transport":"POST","envelope":"JSON-RPC-2.0","contentType":"application\/json","SMDVersion":"2.0","target":"\/json-rpc.php","services":{"processBrowser":{"envelope":"JSON-RPC-2.0","transport":"POST","parameters":[{"type":"object","name":"json","optional":false}],"returns":"string"}},"methods":{"processBrowser":{"envelope":"JSON-RPC-2.0","transport":"POST","parameters":[{"type":"object","name":"json","optional":false}],"returns":"string"}}}{"error":{"code":-32600,"message":"Invalid Request","data":null},"id":null}
The javascript for the code is as follows:
<script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="js/json2.js" type="text/javascript"></script>
<script src="js/jquery.zend.jsonrpc.js" type="text/javascript"></script>
<script src="js/browserDetect.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function()
{
browserInfo = {
"screen_width": screen.width,
"screen_height": screen.height,
"color_depth": screen.colorDepth,
"url": document.URL,
"user_agent": navigator.userAgent,
"browser_name": BrowserDetect.browser,
"browser_version": BrowserDetect.version,
"platform": BrowserDetect.OS
};
redirect = jQuery.Zend.jsonrpc({url: '/json-rpc.php'});
url = redirect.processBrowser(JSON.stringify(browserInfo));
window.location.replace(url);
});
</script>
The jsonrpc.php code is as follows:
<?php
// Define path to the application directory
defined('REFERRAL_SYSTEM_ROOT') || define('REFERRAL_SYSTEM_ROOT', realpath('/system'));
defined('REFERRAL_PUBLIC_ROOT') || define('REFERRAL_PUBLIC_ROOT', realpath('/public'));
require_once REFERRAL_SYSTEM_ROOT . '/some_file.php';
/**
* Zend Application
**/
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application($_ENV["REFERRAL_ENVIRONMENT"], REFERRAL_SYSTEM_ROOT . '/config/application.ini');
$application->getBootstrap();
require_once 'Browser.php';
// Instantiate server, etc.
$server = new Zend_Json_Server();
$server->setClass('Browser');
if('GET' == $_SERVER['REQUEST_METHOD'])
{
// Indicate the URL endpoint, and the JSON-RPC version used:
$server->setTarget('/jsonrpc.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
// Grab the SMD
$smd = $server->getServiceMap();
// Return the SMD to the client
header('Content-Type: application/json');
echo $smd;
}
$server->handle();
As you can see from the response, processBrowser is seen by the ZEND_JSON_RPC server, yet I am getting the "is not a function" response. I'm at a loss as to why this is happening.
Any thoughts?
EDIT -> 4/26/2012 # 4:25 PM EDT
While the function processBrowser() DOES exist, it is part of the Browser class as defined in Browser.php, the call jQuery.Zend.jsonrpc({url: '/json-rpc.php'}) is evidently not receiving a proper response. I still do not know why.
I took the json that you said was from the firebug console and jsonlint it.
Here is the result:
Parse error on line 35:
...g" } }}{ "error": {
--------------------^
Expecting 'EOF', '}', ',', ']'
You have the closing bracket to the whole response before the error section. I am not sure what is generating the response but it needs to be removed from there and place it at the end.
This is the json corrected:
{
"transport": "POST",
"envelope": "JSON-RPC-2.0",
"contentType": "application/json",
"SMDVersion": "2.0",
"target": "/json-rpc.php",
"services": {
"processBrowser": {
"envelope": "JSON-RPC-2.0",
"transport": "POST",
"parameters": [{
"type": "object",
"name": "json",
"optional": false}],
"returns": "string"
}
},
"methods": {
"processBrowser": {
"envelope": "JSON-RPC-2.0",
"transport": "POST",
"parameters": [{
"type": "object",
"name": "json",
"optional": false}],
"returns": "string"
}
}
{
"error": {
"code": -32600,
"message": "Invalid Request",
"data": null
},
"id": null
}
};
I'm having the same issue. Try to remove the line "header('Content-Type: application/json');". It worked for me :)

Categories