I'm stuck at integrating stripe's prebuild payment gateway to my project.
I'm coding very simple Eshop (without login/registration and shopping cart) just a simple project with a form and stripe checkout as a way to pay...
I was following official stripe documentation but I struggle to find an answer how to implement their "simple prebuilt checkout page" to procedural PHP.
Currently I'm stuck on getting this error...the provided code is what I have used from their official documentation "still getting error ReferenceError: sessionId is not defined in the console in devtools ://
Also IDK how to configure endpoint on my server when coding it all without PHP framework such as Slim/Laravel...al examples provided by stripe use Slim framework when configuring endpoints....any ideas?
<?php
//config PHP
require_once("vendor/autoload.php");
// === SET UP STRIPE PAYMENT GATEWAY ===
$stripe = [
"secret_key" => "sk_test_4eC39HqLyjWDarjtT1zdp7dc",
"publishable_key" => "pk_test_TYooMQauvdEDq54NiTphI7jx",
];
\Stripe\Stripe::setApiKey($stripe['secret_key']);
?>
<?php
//create-checkout-session.php
require_once '_includes/config.php';
// ?session_id={CHECKOUT_SESSION_ID} means the redirect will have the session ID set as a query param
$checkout_session = \Stripe\Checkout\Session::create([
'success_url' => 'http://localhost:8888/Avanza---Eshop/success.php?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'http://localhost:8888/Avanza---Eshop/canceled.php',
'payment_method_types' => ['card'], //, 'alipay'
'mode' => 'payment',
'line_items' => [[
'amount' => 2000,
'currency' => 'usd',
'name' => 'mikina',
'quantity' => 1,
]]
]);
header('Content-type: application/json');
echo json_encode(['sessionId' => $checkout_session['id']]);
<!--order.php actual page that will be displayed to users-->
<button style="width: 100px; height: 100px" id="checkout-button"></button>
<script type="text/javascript">
// Create an instance of the Stripe object with your publishable API key
var stripe = Stripe('pk_test_51HjoRfIaBaXJG6udQspXdLRNwMesCriMwZoR7nGCF0hZtu2Zp9FUxCFWwVpwwU4BZs7fTxJtYorVTuoK1vqXp2Uw002r6qvmO7'); // removed for Stackoverflow post
var checkoutButton = document.getElementById('checkout-button');
checkoutButton.addEventListener('click', function() {
// Create a new Checkout Session using the server-side endpoint you
// created in step 3.
fetch('create-checkout-session.php', {
method: 'POST',
})
.then(function(response) {
return response.json();
})
.then(function(session) {
return stripe.redirectToCheckout({ sessionId: sessionId});
})
.then(function(result) {
// If `redirectToCheckout` fails due to a browser or network
// error, you should display the localized error message to your
// customer using `error.message`.
if (result.error) {
alert(result.error.message);
}
})
.catch(function(error) {
console.error('Error:', error);
});
});
</script>
I think you need to replace return stripe.redirectToCheckout({ sessionId: sessionId}); with return stripe.redirectToCheckout({ sessionId: session.sessionId});
It's worked for me. If you see more errors or face any problems, loot at the browser console Network tab.
$(function() {
var stripe = Stripe('<?= Config::STRIPE_PUB_KEY ?>'); // here write: pk_test_5...
$(document).on('click', '.buy_now_btn', function(e) {
let id = $(this).attr('id');
$(this).text('Please wait...');
$.ajax({
url: 'action.php',
method: 'post',
data: {
id: id,
stripe_payment_process: 1
},
dataType: 'json',
success: function(response) {
console.log(response);
return stripe.redirectToCheckout({
sessionId: response.id
});
},
})
})
});
Related
I have a react app Im working on to create a new frontend for an already live woocommerce site. I'm using this endpoint /wp-json/wc/store/v1/cart/add-item like so -
let config = {
method: "post",
url: "http://localhost:8010/proxy/wp-json/wc/store/v1/cart/add-item",
data: {
id : id,
quantity: 1,
variation: [
{
attribute: "Color",
value: color,
},
{
attribute: "Size",
value: size,
}
]
}
}
console.log(config)
const resp = await axios(config).then((response) => {
console.log(response.data)
})
.catch((error) => {
console.log(error.response.data);
});
Which is giving me a successful json response showing I have the item added -
items_count: 1
Then I have a cart component to api call and render -
useEffect(() => {
getCart();
}, []);
const getCart = async () => {
let config = {
method: "get",
url: "http://localhost:8010/proxy/wp-json/wc/store/v1/cart"
}
await axios(config).then((response) => {
console.log(response.data)
})
.catch((error) => {
console.log(error.response.data);
});
}
However when navigating to this page/component or any other, the api call is returning an empty cart - items_count: 0
On the checkout page I tried using a different endpoint wp-json/wc/store/v1/checkout but this is giving me an error -
code: "woocommerce_rest_cart_empty" data: {status: 400} message: "Cannot create order from empty cart."
Any ideas why this is happening?
It's possible that the request isn't setting a cookie which will prevent the cart from working as expected. In my experience, I can make a build of my React app and activate it as a WordPress theme. Then the add-to-cart works as expected. But if I'm using the live preview of the app instead, the add-to-cart will not work because the cookie is missing. Here's a GitHub issue about it.
https://github.com/woocommerce/woocommerce-blocks/issues/5683
I am working on a django website and have come across an error which I am not able to solve and Its been a couple of days but I wasnt able to solve the error. I am trying to integrate a payment gateway to my site. I have a payment button which on click is supposed to post the data to the database as well as go to the payment site. But it is storing the data but not going to payment site.
Here is the javascript for my button:
document.getElementById('payment-info').addEventListener('click', function (e) {
submitFormData()
})
function submitFormData() {
console.log('Payment Button Clicked')
var userFormData = {
'name': null,
}
var shippingInfo = {
'address': null,
}
shippingInfo.address = form.address.value
userFormData.name=form.name.value
var url = "/process_order/"
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
body:JSON.stringify({'form': userFormData, 'shipping': shippingInfo }),
})
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
alert('Transaction Completed')
window.location.href = "{% url 'index' %}"
})
}
</script>
This is my views.py:
def processOrder(request):
transaction_id = datetime.datetime.now().timestamp()
data = json.loads(request.body)
if request.user.is_authenticated:
customer=request.user.customer
order, created=Order.objects.get_or_create(customer=customer, complete=False)
total=float(data['form']['total'])
order.transaction_id=transaction_id
if total == order.get_cart_total:
order.complete = True
order.save()
ShippingAddress.objects.create(
customer=customer,
order=order,
address=data['shipping']['address'],
name=data['form']['name'],
)
//Code for integration below
param_dict = {
'MID': 'DIY12386817555501617',
'ORDER_ID': str(order.id),
'TXN_AMOUNT': '4',
'CUST_ID': 'j',
'INDUSTRY_TYPE_ID': 'Retail',
'WEBSITE': 'WEBSTAGING',
'CHANNEL_ID': 'WEB',
'CALLBACK_URL':'http://127.0.0.1:8000/handlerequest/',
}
param_dict['CHECKSUMHASH'] = Checksum.generate_checksum(param_dict, MERCHANT_KEY)
return render(request, 'paytm.html', {'param_dict': param_dict})
return JsonResponse('Done',safe=False)
#csrf_exempt
def handlerequest(request):
# paytm will send you post request here
form = request.POST
response_dict = {}
for i in form.keys():
response_dict[i] = form[i]
if i == 'CHECKSUMHASH':
checksum = form[i]
verify = Checksum.verify_checksum(response_dict, MERCHANT_KEY, checksum)
if verify:
if response_dict['RESPCODE'] == '01':
print('order successful')
else:
print('order was not successful because' + response_dict['RESPMSG'])
return HttpResponse('doneee')
And this is my urls.py:
path("process_order/",views.processOrder,name="process_order"),
path("handlerequest/",views.handlerequest,name="handlerequest"),
This code is not working . After clicking the payment button I am getting this error:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
This error is referring to the submitformdata() in my javascript code.
I want to workout a way so that once a person clicks on the payment button and his transaction is completed then his data is submitted to the database otherwise not for which I have written the code in handlerequest.
Please help me out.
Since three days i am trying to get the Paypal Checkout to work but i always have the problem that the order is created and the money in gone from the buying account but not reaching the payee account.
So here is my setup:
The Smart Buttons integeration in JavaScript:
paypal.Buttons({
env: enviroment,
// Set up the transaction
createOrder: function() {
let formData = new FormData();
formData.append('bookingId', bookingId);
return fetch (url_createOrder, {
method: 'POST',
body: formData
}).then(response => {
console.log(response);
return response.json()
})
.then(function(res) {
console.log(res);
return res.result.id;
});
},
// Finalize the transaction
onApprove: function(data, actions) {
console.log(data);
// This function captures the funds from the transaction.
return actions.order.capture().then(function(details) {
console.log(details);
// This function shows a transaction success message to your buyer
// window.location.href = 'danke.php';
});
}
}).render('#paypal-button-container');
As you can see the createOrder starts a AJAX call to this script:
[...]
$client = new PayPalHttpClient($environment);
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = self::buildRequestBody($price);
// 3. Call PayPal to set up a transaction
$response = $client->execute($request);
echo json_encode($response, JSON_PRETTY_PRINT);
// 4. Return a successful response to the client.
return $response;
}
private static function buildRequestBody($price) {
return array(
'intent' => 'CAPTURE',
'application_context' => array(
'brand_name' => 'Example',
'cancel_url' => 'http://localhost/example/abbruch.php',
'return_url' => 'http://localhost/example/danke.php'
),
'purchase_units' => array(
0 => array(
'reference_id' => 'example_addr',
'description' => 'example Address',
'amount' => array(
'currency_code' => 'EUR',
'value' => $price
)
)
)
);
[...]
Everything works so far to this point. I get a OrderId back which i return to the AJAX call and then i am am able to insert credentials and pay the given price.
When i finish the payment the onApprove of the smart buttons in the JS file get called back and i also get the correct response of that actions.order.capture():
{create_time: "2020-08-14T19:37:59Z", update_time: "2020-08-14T19:38:20Z", id: "6FP46164U47878440", intent: "CAPTURE", status: "COMPLETED", …}
create_time: "2020-08-14T19:37:59Z"
id: "6FP46164U47878440"
intent: "CAPTURE"
links: [{…}]
payer:
address:
country_code: "DE"
__proto__: Object
email_address: "sb-ughwh2901918#personal.example.com"
name: {given_name: "John", surname: "Doe"}
payer_id: "8Z5RM2ERW6VTL"
__proto__: Object
purchase_units: [{…}]
status: "COMPLETED"
update_time: "2020-08-14T19:38:20Z"
__proto__: Object
Afterwards the money is gone from the buyer account but it says "pending", here a screenshot (but in german)
payment_is_pending.png
On the seller account i can´t select anything like "approve". I found an example of the paypal checkout api which works similar and tried to copy it into my code but yeah... same story.
Then i thought maybe the problem is the seller sandbox account, but if i try it which an sandbox account created and given by a paypal tutorial is says pending as well.
Please, help!
The payments are pending because there is no sandbox account with the email sb-2xact2876961#business.example.com confirmed, so the payments are in an unclaimed state. Pending unclaimed payments will be automatically returned after 30 days if left unclaimed.
To claim the payments, the email sb-2xact2876961#business.example.com must be confirmed on a sandbox account, via https://www.sandbox.paypal.com/businessprofile/settings/email and https://developer.paypal.com/developer/notifications/
Stripe are soon to roll out their use of Strong Customer Authentication for payments with their platform. There's a fairly substantial section in their documentation about it.
https://stripe.com/docs/payments/payment-intents/quickstart#manual-confirmation-flow
The process has the following flow:
The vanilla PHP implementation is like so:
<?php
# vendor using composer
require_once('vendor/autoload.php');
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
header('Content-Type: application/json');
# retrieve json from POST body
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$intent = null;
try {
if (isset($json_obj->payment_method_id)) {
# Create the PaymentIntent
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $json_obj->payment_method_id,
'amount' => 1099,
'currency' => 'gbp',
'confirmation_method' => 'manual',
'confirm' => true,
]);
}
if (isset($json_obj->payment_intent_id)) {
$intent = \Stripe\PaymentIntent::retrieve(
$json_obj->payment_intent_id
);
$intent->confirm();
}
generatePaymentResponse($intent);
} catch (\Stripe\Error\Base $e) {
# Display error on client
echo json_encode([
'error' => $e->getMessage()
]);
}
function generatePaymentResponse($intent) {
# Note that if your API version is before 2019-02-11, 'requires_action'
# appears as 'requires_source_action'.
if ($intent->status == 'requires_action' &&
$intent->next_action->type == 'use_stripe_sdk') {
# Tell the client to handle the action
echo json_encode([
'requires_action' => true,
'payment_intent_client_secret' => $intent->client_secret
]);
} else if ($intent->status == 'succeeded') {
# The payment didn’t need any additional actions and completed!
# Handle post-payment fulfillment
echo json_encode([
"success" => true
]);
} else {
# Invalid status
http_response_code(500);
echo json_encode(['error' => 'Invalid PaymentIntent status']);
}
}
?>
The necessary JavaScript for its use with Stripe Elements looks like this:
var cardholderName = document.getElementById('cardholder-name');
var cardButton = document.getElementById('card-button');
cardButton.addEventListener('click', function(ev) {
stripe.createPaymentMethod('card', cardElement, {
billing_details: {name: cardholderName.value}
}).then(function(result) {
if (result.error) {
// Show error in payment form
} else {
// Otherwise send paymentMethod.id to your server (see Step 2)
fetch('/ajax/confirm_payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_method_id: result.paymentMethod.id })
}).then(function(result) {
// Handle server response (see Step 3)
result.json().then(function(json) {
handleServerResponse(json);
})
});
}
});
});
function handleServerResponse(response) {
if (response.error) {
// Show error from server on payment form
} else if (response.requires_action) {
// Use Stripe.js to handle required card action
stripe.handleCardAction(
response.payment_intent_client_secret
).then(function(result) {
if (result.error) {
// Show error in payment form
} else {
// The card action has been handled
// The PaymentIntent can be confirmed again on the server
fetch('/ajax/confirm_payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_intent_id: result.paymentIntent.id })
}).then(function(confirmResult) {
return confirmResult.json();
}).then(handleServerResponse);
}
});
} else {
// Show success message
}
}
In my own project I'm using Laravel which is entirely based on the MVC architecture and it fairly nice to you when it comes to most things.
I have tried to refactor a little but I have a question.
Why would you use this line $json_str = file_get_contents('php://input'); over just trying to grab the posted variables from the Request object used in Laravel?
I also read the following article from the PHP Manual:
https://www.php.net/manual/en/wrappers.php.php
To be perfectly honest I've been away from procedural PHP so this has confused me to no end.
Why use 'php://input' over the POST superglobal - Stripe SCA example
The body is encoded as JSON. You can tell because the next line explicitly decodes it.
PHP doesn't understand application/json requests. It will only populate $_POST if the data is encoding using the application/x-www-form-urlencoded or multipart/form-data formats.
Why would you use this line $json_str = file_get_contents('php://input'); over just trying to grab the posted variables from the Request object used in Laravel?
If you were using Laravel, there's no reason to do that.
Since there is no sign of anything Laravel in the example you gave, it is presumably not written with the intention of introducing a dependency on Laravel.
I have a little moment that I don't understand because I'm new to development.
I'm collecting data from multi step form and want to handle all form inputs at one ajax request on my controlle. I did it successfully, but can't figure out how to use data from $request if it's an array from ajax.
I can use if it $request->input('name') but in my case I need something like $request->input('firstGrant.issue_date') because of my data format. Please tip me which way to dig.
My method:
submitCompany() {
axios.post('/onboarding', {
name: this.step1.name,
type: this.step1.type,
shares_amount: this.step2.shares_amount,
par_value: this.step2.par_value,
firstGrant: {
issue_date: this.step3.firstGrant.issue_date,
certificate: this.step3.firstGrant.certificate,
share_price: this.step3.firstGrant.share_price,
shares_amount: this.step3.firstGrant.shares_amount
}
})
.then(function (response) {
console.log(response);
alert('Information saved!');
})
.catch(function (error) {
console.log(error);
alert('Wrong!');
});
}
My Controller:
public function store(Request $request)
{
$userId = Auth::user()->id;
$issueDate = $request->input('firstGrant.issue_date'); //How to do it right way?
$certificate = $request->input('firstGrant.certificate');//How to do it right way?
$sharePrice = $request->input('firstGrant.share_price');//How to do it right way?
$sharesAmount = $request->input('firstGrant.shares_amount');//How to do it right way?
$equityGrant = EquityGrant::create([
'user_id' => $userId,
'share_id' => 91,
'vesting' => 0,
'status' => 'active',
'issue_date' => $issueDate,
'certificate' => $certificate,
'share_price' => $sharePrice,
'shares_amount' => $sharesAmount,
]); }
You might have to configure axios to send a header along with every request that will make Laravel recognize the request as being XHR. Once it does, the $request->input('x.y') statements should work.
Object.assign(axios.defaults.headers, {
'X-Requested-With': 'XMLHttpRequest',
});
If this still does not work you might also want to check whether axios properly includes the CSRF-token in a request header.