Check if Google Pay is available with JS - javascript

There is a system called Engaging Networks where the system provides payment methods like Apple Pay or Google Pay. I would like to show/hide the relevant payment button whether the payment type is available or not.
I know that I can check Apple Pay simply with window.ApplePaySession but I can't see how to check Google Pay availability.
I can see the request has been sent to https://pay.google.com/gp/p/ui/pay, but basically that's it.
Is there any way to check this?

As called out by #esqew, here is an example of how to call isReadyToPay:
function onGooglePayLoaded() {
const client = new google.payments.api.PaymentsClient({
environment: 'TEST',
merchantInfo: {
merchantId: '12345678901234567890',
merchantName: 'Demo Merchant',
},
});
const readyToPayOptions = {
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [
{
type: 'CARD',
parameters: {
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
allowedCardNetworks: ['MASTERCARD', 'VISA'],
},
tokenizationSpecification: {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'example',
},
},
},
],
};
client.isReadyToPay(readyToPayOptions).then(result => console.log('Is ready to pay: ', result));
}
<script
async
src="https://pay.google.com/gp/p/js/pay.js"
onload="onGooglePayLoaded()">
</script>

Related

Credimax hosted checkout payment always return "Unsuccessful Payment" in response?

I am using the Credimax hosted checkout payment gateway. After getting the session id from the server, I'm trying to do a test transaction using Credimax testing cards, but it always show the "Unsuccessful Payment" response from the server with 200 code.
The below link shows the official documentation.
https://credimax.gateway.mastercard.com/api/documentation/integrationGuidelines/hostedCheckout/integrationModelHostedCheckout.html?locale=en_US#x_obtainThePaymentResult
You can also check this documentation too,
https://credimax.gateway.mastercard.com/api/documentation/integrationGuidelines/index.html
This is what I have done so far.
<script type="text/javascript">
function errorCallback(error) {
console.log(JSON.stringify(error));
}
function cancelCallback() {
console.log('Payment cancelled');
}
$( document ).ready(function() {
console.log( "ready!" );
});
Checkout.configure({
merchant: 'E18009950',
session: {
id: 'SESSION0002013654327E6XXXX8'
},
interaction: {
operation : "PURCHASE",
merchant: {
name: 'XYZZZ',
address: {
line1: '200 Sample St',
line2: '1234 Example Town'
}
},
},
order: {
// amount : "12.0",
// currency : "BHD",
description: "Ordered Goods",
id: "2325487321"
}
});
</script>
This script loads the payment page successfully but throws this error at the beginning of the page;
Let me know if anyone has faced this issue and found any solution.

PayPal Smart Buttons Error: "Expected order id to be passed"

i have a problem : I'm trying to figure out what it is since last friday, I can't find any good docs and no clues on the internet, I share some screenshots if anyone could help it would be awesome, by the way my problem is that when clicking on the paypal smart buttons that I integrated, i get in the console "expected an order id to be passed" unfortunately I can't find what is that order id thing
paypal.Buttons({
style: {
shape: 'rect',
color: 'gold',
layout: 'vertical',
label: 'pay',
},
// Sets up the transaction when a payment button is clicked
createOrder: function (data, actions) {
var cartArray = shoppingCart.listCart();
// Call your backend to create the Checkout Session
$.ajax({
data: {
id: cookie
},
type: "POST",
url: "create.php",
success: function (response) {
response = JSON.parse(response)
surname = []
surname = response.name.split(/(\s+)/).filter(e => e.trim().length > 0)
const Cart5 = [];
function Cart(description, name, unit_amount, quantity) {
this.description = description;
this.name = name;
this.unit_amount = {
value: unit_amount,
currency_code: 'EUR'
};
this.quantity = quantity;
this.category = 'PHYSICAL_GOODS';
}
cartArray.forEach(element => {
var item = new Cart(element.id, element.name, element.price, element.count);
Cart5.push(item);
})
JSON.stringify(Cart5);
orderid = makeid(12);
const paymentData = {
//authorization: 'AdhHUVsamn71V-Xs5JZVpzL4v6ElEKiYywV6PwF7rRwCwRQ-AZHMcLELmvQuWlS1pL19iiCbbZUIupTt',
intent: "CAPTURE",
env: "production",
application_context: {
brand_name: "Skunker",
locale: "fr-FR",
landing_page: "BILLING",
shipping_preference: "SET_PROVIDED_ADDRESS",
},
purchase_units: [{
reference_id: orderid,
custom_id: orderid,
description: 'Achat chez Skunker.Store',
invoice_id: orderid,
payer: {
email_address: response.email,
},
amount: {
currency_code: "EUR",
value: shoppingCart.totalCart() - (shoppingCart.totalCart() * sessionStorage.getItem('discount') / 100) + 6.15,
breakdown: {
item_total: {
currency_code: "EUR",
value: shoppingCart.totalCart()
},
tax_total: {
currency_code: "EUR",
value: 0.20
},
shipping: {
currency_code: "EUR",
value: 5.95
},
handling: {
currency_code: "EUR",
value: 0.00
},
insurance: {
currency_code: "EUR",
value: 0.0
},
shipping_discount: {
currency_code: "EUR",
value: 0.00
}
}
},
items: Cart5,
shipping: {
method: "La Poste - Colissimo",
address: {
name: {
given_name: surname[0],
surname: surname[1],
},
address_line_1: response.address,
admin_area_2: response.city,
postal_code: response.postalCode,
country_code: "FR"
},
phone_number: {
country_code: '33',
national_number: response.tel,
}
}
}]
}
return actions.order.create(paymentData);
}
})
},
// Finalize the transaction after payer approval
onApprove: function (data, actions) {
return actions.order.capture().then(function (orderData) {
// Full available details
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
// Show a success message within this page, e.g.
const element = document.getElementById('paypal-button-container');
element.innerHTML = '';
element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Successful capture! For dev/demo purposes:
$.ajax({
data: JSON.stringify(paymentData),
type: "POST",
url: "https://skunker.store/scripts/paid.php",
success: function (response) {}
})
// When ready to go live, remove the alert and show a success message within this page. For example:
// var element = document.getElementById('paypal-button-container');
// element.innerHTML = '';
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Or go to another URL: actions.redirect('thank_you.html');
});
},
onError: function (err) {
console.log(err);
},
}).render('#payBtn');
And this is the error I get :
Error: Expected an order id to be passed
at https://www.sandbox.paypal.com/smart/buttons?style.label=pay&style.layout=vertical&style.color=gold&style.shape=rect&style.tagline=false&style.menuPlacement=below&components.0=buttons&locale.country=FR&locale.lang=fr&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QVhTMWxLcXR2cjkzbDVkYlFPTE9nclJCYlNKMWt0cmNnYkpMZnJjRWEyckhING1ZYzVvWlQ1dmxpWUZDMnRobUFlcDVic1h4RmF1WEJ1cDMmY3VycmVuY3k9RVVSIiwiYXR0cnMiOnsiZGF0YS1zZGstaW50ZWdyYXRpb24tc291cmNlIjoiYnV0dG9uLWZhY3RvcnkiLCJkYXRhLXVpZCI6InVpZF9tdmh4dGh4aHhlYW13bHJzYXVna2dqeGRmcmpqenMifX0&clientID=AXS1lKqtvr93l5dbQOLOgrRBbSJ1ktrcgbJLfrcEa2rHH4mYc5oZT5vliYFC2thmAep5bsXxFauXBup3&sdkCorrelationID=f540177905bdc&storageID=uid_dbb0ba13c9_mtq6mzg6ndi&sessionID=uid_0e8f15ce50_mtq6ntq6nte&buttonSessionID=uid_1e5135ffcf_mtq6ntq6nte&env=sandbox&buttonSize=huge&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwibWVyY2hhbnRDb25maWdIYXNoIjoiZmQxNWMxYTBkNTFiYjBlMTRjODkxYTUzNDYwZTZiYWU1MDkyZmEzZCIsInByb2R1Y3RzIjp7InBheUluMyI6eyJlbGlnaWJsZSI6ZmFsc2UsInZhcmlhbnQiOm51bGx9LCJwYXlJbjQiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXJpYW50IjpudWxsfSwicGF5bGF0ZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXJpYW50IjpudWxsfX19LCJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJicmFuZGVkIjp0cnVlLCJpbnN0YWxsbWVudHMiOmZhbHNlLCJ2ZW5kb3JzIjp7InZpc2EiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sIm1hc3RlcmNhcmQiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sImFtZXgiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sImRpc2NvdmVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiaGlwZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXVsdGFibGUiOmZhbHNlfSwiZWxvIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfX0sImd1ZXN0RW5hYmxlZCI6ZmFsc2V9LCJ2ZW5tbyI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpdGF1Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImNyZWRpdCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJhcHBsZXBheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJzZXBhIjp7ImVsaWdpYmxlIjpmYWxzZX0sImlkZWFsIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJhbmNvbnRhY3QiOnsiZWxpZ2libGUiOmZhbHNlfSwiZ2lyb3BheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlcHMiOnsiZWxpZ2libGUiOmZhbHNlfSwic29mb3J0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm15YmFuayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwMjQiOnsiZWxpZ2libGUiOmZhbHNlfSwiemltcGxlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ3ZWNoYXRwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwicGF5dSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJibGlrIjp7ImVsaWdpYmxlIjpmYWxzZX0sInRydXN0bHkiOnsiZWxpZ2libGUiOmZhbHNlfSwib3h4byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtYXhpbWEiOnsiZWxpZ2libGUiOmZhbHNlfSwiYm9sZXRvIjp7ImVsaWdpYmxlIjpmYWxzZX0sIm1lcmNhZG9wYWdvIjp7ImVsaWdpYmxlIjpmYWxzZX19&platform=desktop&experiment.enableVenmo=false&experiment.disablePaylater=false&experiment.enableVenmoAppLabel=false&flow=purchase&currency=EUR&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false&allowBillingPayments=true:1338:178001
I tried putting only the amount into the data and it still doesn't work, I also tried to add an order ID but it doesn't work
This is a bit of a mess, you're doing an ajax call to a "create.php" on your server, but for some reason not calling the PayPal API from there (with the Checkout-PHP-SDK or similar), but are instead using that response to then create an order from the client-side (which is what actions.order.create does)
This doesn't make any real sense. If you are using a server, you should have two routes: create.php and capture.php?id=XXXXXXXXXXXXXXX" (use a JSON body parameter to fetch rather than GET URL string, if desired) both of which communicate with the PayPal API themselves, to create and capture an order respectively. It does not make sense to combine your own server operations with JS SDK client-side methods.
So, you should switch over completely to this server pattern example: https://developer.paypal.com/demo/checkout/#/pattern/server , and in each of the respective routes that are called (create.php / capture.php or similar) you can either write your own HTTPS calls for the PayPal API, or use the Checkout-PHP-SDK to abstract them as desired, and return the JSON response to the fetch caller.
I do not recommend trying to get what you have to work, but the main reason it is not working is a failure to return a JavaScript Promise properly. You are invoking an asynchronous $.ajax and not returning anything after doing so, hence the error "Expected an order id to be passed" since you actually returned nothing (even though you think you did); in reality you just spun off an asynchronous $.ajax to do its own thing and that function's result is never fed back (nor would it be if you returned its result, since it uses a callback rather than promises).
The simplest way to get a promise when calling your own server routes is to use fetch instead of $.ajax, then you can just return the result of the fetch. It is theoretically possible to turn a $.ajax callback into a promise and return that, but I would not spend any time on this if I were you; the built-in browser fetch creates a promise for you and is preferred in modern JS.

Stripe elements - issue with apple pay - payment window appear and disappear in a second

I connected Stipe payments to the site using js API v3 and stripe elements. Everything works (including google pay) expect apple pay. When a user clicks on apple pay button - payment window appears just for a brief second and then disappear. The site domain was verified according to Stripe wiki for js v2, v3 doesn't have such page. Can't find any errors. Will be grateful for any hints or even direction. Thank you.
Code sample:
paymentRequest = stripe.paymentRequest({
country: 'GB',
currency: 'gbp',
total: {
label: 'Upgrade',
amount: 11400,
},
requestPayerName: false,
requestPayerEmail: true,
});
var prButton = elements.create('paymentRequestButton', {
paymentRequest: paymentRequest,
});
paymentRequest.canMakePayment().then(function (result) {
if (result) {
prButton.mount('#payment-request-button');
} else {
document.getElementById('payment-request-error').innerHTML = "Your browser doesn't support Google or Apple Wallet";
document.getElementById('payment-request-button').style.display = 'none';
}
paymentRequest.on('paymentmethod', function (ev) {
stripe.confirmCardPayment(
clientSecret, {
payment_method: ev.paymentMethod.id
}, {
handleActions: false
}
).then(function (confirmResult) {
if (confirmResult.error) {
ev.complete('fail');
} else {
ev.complete('success');
if (confirmResult.paymentIntent.status === "requires_action") {
stripe.confirmCardPayment(clientSecret).then(function (result) {
if (result.error) {
alert("Error, try new payment method");
} else {
orderComplete(confirmResult.paymentInten.id);
}
});
} else {
orderComplete(confirmResult.paymentInten.id);
}
}
});
});
/*
Some code
*/
// update request price if user select diffirent price
paymentRequest.update({
total: {
label: 'Upgrade',
amount: finalPrice * 100,
},
})
Does Apple Pay work for you in the example in the docs? Do you have an example of your implementation available online somewhere to access, or can you reproduce this in a JSFiddle or CodeSandbox?
Two suggestions to try:
In your calls to orderComplete you appear to have a typo on paymentInten**t**.id -- missing the t at the end in both instances.
I wonder if your paymentRequest.update is causing issues. I'm not familiar with the behaviour of this part of the API so I'd recommend disabling to simplify diagnostics.

Razor Pay checkout form not appearing and giving error as not a function

I am implementing razorPay payment in angular7 project.I am trying to open checkout form by creating a single instance of Razorpay and accessing its function open(). But instead it is throwing error "is not a function". I couldn't find any proper documentation regarding this.
However, If I try to simple create payment using razorpay, it opens up the window but there is no option for user to choose any method and hence it throws error again because directly creating payment will not add up any card(if method is 'card'). So it is necessary to open checkout form.
Here is my function I am using, firstly i create order on server to generate id and then proceed to payment.
buyPlan() {
let postdata = {
amount: 1000,
currency: "INR",
receipt: "1",
notes: {},
payment_capture: true
}
this.common.createOrder(postdata).subscribe(
(result: any) => {
console.log(result)
var razorpay = new this.winRef.nativeWindow.Razorpay({
key: 'dashboard_key_id',
image: 'assets/images/logo-1.png',
});
var data = {
amount: 1000,
currency: "INR",
email: 'abc#example.com',
contact: '9874563210',
notes: {
address: 'Sector 65 Delhi',
},
method: 'card',
order_id: result.data.id,
handler: function (response) {
alert(response.razorpay_payment_id);
}
};
razorpay.open();
}, (err: HttpErrorResponse) => {
}
);
}
For Custom Integration
Remove:
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
from index.html file
and put:
<script type="text/javascript" src="https://checkout.razorpay.com/v1/razorpay.js"></script>
inside <head></head> tag

Simulate PayPal errors in a sandbox account

I'm integrating PayPal payment on a web application I'm developing. I need to create an authorization for a transaction where I lock an amount of money (let's say 20€), then at the end of the transaction I complete the transaction and I take only the money that I need to take (so if the transaction's final cost is 15€, I give back 5€ to the user).
This workflow is currently working on a sandbox account, but now I wanted to test some errors that may occur while starting a new transaction, like for instance when the user doesn't have the sufficient amount of money (20€) that I need to lock in order to start a new transaction.
I found this documentation (https://developer.paypal.com/docs/api/test-values/#invoke-negative-testing) where it is stated To trigger the SENDER_EMAIL_UNCONFIRMED simulation response, set the items[0]/note value to ERRPYO002 in the POST v1/payments/payouts call. with the following code:
curl -X POST https://api.sandbox.paypal.com/v1/payments/payouts \
-H "content-type: application/json" \
-H "Authorization: Bearer Access-Token" \
-d '{
"sender_batch_header": {
"sender_batch_id": "1524086406556",
"email_subject": "This email is related to simulation"
},
"items": [
{
"recipient_type": "EMAIL",
"receiver": "payouts-simulator-receiver#paypal.com",
"note": "ERRPYO002",
"sender_item_id": "15240864065560",
"amount": {
"currency": "USD",
"value": "1.00"
}
}]
}'
So I guess that I need to pass an error code (like ERRPYO002) to a note field in my request body.
I'm using the checkout sdk, and my js code currently looks like this:
const buttonOpts = {
env: 'sandbox',
client: { production: $scope.key, sandbox: $scope.key },
style: {
label: 'paypal',
size: 'medium',
shape: 'rect',
color: 'blue',
tagline: false,
},
validate: actions => {
// stuff
},
payment: (data, actions) => {
return actions.payment.create({
intent: 'authorize',
payer: { payment_method: 'paypal' },
transactions: [
{
amount: {
total: '20.00',
currency: 'EUR',
},
description: 'My description',
},
],
});
},
onAuthorize: data => {
// Sending data.paymentID and data.payerID to my backend to confirm the new transaction
},
onCancel: () => {
// stuff
},
onError: err => {
console.log(err);
// stuff
},
};
Paypal.Button.render(buttonOpts, '#paypal-button');
I guess that I need to pass the code needed to simulate the error to my actions.payment.create object parameter, but I didn't find where exactly since my workflow is different that the one in the docs.
These are the codes that PayPal allows you to use for error testing:
https://developer.paypal.com/docs/payouts/integrate/test-payouts/#test-values
Any help is appreciated.
Thanks a lot.
Ok, I've actually found out how to solve this problem right after I posted this question.
I'll just put my solution here for anyone that may have this problem in the future.
The option object I posted is actually correct as it is now, so after the user confirms that he/she wants to start a new transaction I get the payerID and the paymentID to send to my backend.
On my backend function I changed my code so that it is as follows:
const paypal = require('paypal-rest-sdk');
const paymentId = event.paymentID;
const payerId = { payer_id: event.payerID };
paypal.configure({
mode: process.env.PAYPAL_ENVIRONMENT, //sandbox or live
client_id: '<MY_CLIENT_ID>',
client_secret: '<MY_CLIENT_SECRET>',
});
paypal.payment.execute(
paymentId,
payerId,
// START NEW CODE
{
headers: {
'Content-Type': 'application/json',
'PayPal-Mock-Response': '{"mock_application_codes": "INSUFFICIENT_FUNDS"}',
},
},
// END NEW CODE
(error, payment) => {
console.error(JSON.stringify(error));
console.error(JSON.stringify(payment));
if (error) {
/*
{
"response": {
"name": "INSUFFICIENT_FUNDS",
"message": "Buyer cannot pay - insufficient funds.",
"information_link": "https://developer.paypal.com/docs/api/payments/#errors",
"debug_id": "a1b2c3d4e5f6g",
"details": [
{
"issue": "The buyer must add a valid funding instrument, such as a credit card or bank account, to their PayPal account."
}
],
"httpStatusCode": 400
},
"httpStatusCode": 400
}
*/
return callback('unhandled_error', null);
}
if (payment.state === 'approved' && payment.transactions && payment.transactions[0].related_resources && payment.transactions[0].related_resources[0].authorization) {
return callback(null, payment.transactions[0].related_resources[0].authorization.id);
}
console.log('payment not successful');
return callback('unhandled_error', null);
}
);
In the request headers you just have to put an header called PayPal-Mock-Response that contains the error code you want to test, and that's it.
Hope this'll help somebody!

Categories

Resources