I am testing a web app with a PayPal express checkout button
I click on Pay now, I log-in with one of my sandbox accounts and pay with Paypal fundings, but payment doesn't end well and I receive a 400 error: {"ack":"contingency","contingency":"INSTRUMENT_DECLINED","meta":...
my code is
paypal.button.render({
env: 'sandbox',
client: {
sandbox: 'AAAAAAAAAAA',
production: '<????>'
},
locale: 'en_US',
commit: true, // Show a 'Pay Now' button
style: {
size:'medium',
color: 'silver',
label: 'pay',
},
payment: function(data, actions) {
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: ctrl.amount, currency: 'EUR' }
}
]
},
experience: {
input_fields: {
no_shipping: 1
}
},
});
},
onAuthorize: function(data, actions) {
return actions.payment.execute().then(function(payment) {
alert("Payment completed!");
paymentCompleted();
});
},
onCancel: function(data, actions) {
alert("Payment doesn't end well :-(");
location.href=location.href;
}
}, '#paypal-button');
I noticed the same behaviour in interactive demo, I can login, pay, but the payment is not accepted due to INSTRUMENT_DECLINED.
Any idea about where can be the problem?
I tried to create different sandbox accounts, but nothing changes.
Related
i have one form if user enter his details on his form and submit form, after submit form it stores to database and after successfully store users data in database only then i have to open paypal checkout modal otherwise not.
this is paypal
paypal.Button.render({
env: 'sandbox',
client: {
sandbox: ''
// production: 'demo_production_client_id'
},
locale: 'en_US',
style: {
layout: 'horizontal',
size: 'small',
color: 'blue',
shape: 'pill',
label: 'checkout',
height: 40,
tagline: 'false'
},
commit: true,
payment: (data, actions) => {
return actions.payment.create({
transactions: [{
amount: {
total: '1',
currency: 'USD'
}
}]
});
},
onAuthorize: function(data, actions) {
return actions.payment.execute()
.then(function() {
window.alert('Thank you for your purchase!');
});
}
}, this.paypalRef.nativeElement);
this is submit form api call
submit(){
const data={
url: this.URL,
email:this.email
}
this.home.websiteScratching(data)
.subscribe(res=>{
},err=>{
console.log(err);
})
}
after submit success response i want to go for paypal checkout process how to do it.. i am stuck.
In short you have to create new component and use dialogRef.
https://material.angular.io/components/dialog/overview
const dialogRef = this.dialog.open(SuccessPaymentPaypalComponent, {
disableClose: true,
data: { PaypaplRetunrnTrasactionId: this.params.Paypalid }
})
dialogRef.afterClosed().subscribe(() => {
});
I finished my app and I am planning to host it online. Can my clients use sandbox accounts to make real transactions? This is my first time developing an app and making it have real online transactions using Paypal. Does it have something to do with coding or I have to change a setting in Paypal itself?
Payments.vue
<template>
<div>
<div ref="paypal"></div>
</div>
</template>
mounted()
{
const script = document.createElement("script");
script.src =
"https://www.paypal.com/sdk/js?client-MY-CLIENT-ID";
script.addEventListener("load", this.setLoaded);
document.body.appendChild(script);
}
methods: {
setLoaded: function () {
this.loaded = true;
window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
// description: this.product.description,
amount: {
currency_code: "USD",
value: this.product.price,
},
},
],
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
this.$q.notify({
message: "Transaction Successful!",
color: "green",
actions: [
{
label: "Dismiss",
color: "white",
handler: () => {
/* ... */
},
},
],
});
let dateObj = new Date();
let month = dateObj.getMonth();
let day = dateObj.getDate();
let year = dateObj.getFullYear();
let output = month + "" + day + "" + year;
this.$store
.dispatch("SAVE_ENTRY", {
username: this.username,
password: this.password,
confirmPass: this.confirmPass,
access_id: output + this.newAccData,
chosenSchoolId: this.chosenSchoolId,
})
.then((res) => {
if (res.data === "Success1") {
this.$q.notify({
message:
"Transaction Successful! Please complete your registration process inside the website.",
color: "green",
actions: [
{
label: "Dismiss",
color: "white",
handler: () => {
/* ... */
},
},
],
});
}
});
console.log(order);
},
onError: (err) => {
console.log(err);
},
})
.render(this.$refs.paypal);
},
}
I believe there's a sandbox environment, on https://sandbox.paypal.com/ . You have to change the API endpoint to something like that. The sandbox uses separate accounts that can be made in the developer environment on PayPal API pages.
You should be able to set up sandbox accounts here:
https://developer.paypal.com/developer/accounts/
However I dont think this is supposed to be a Javascript/Vue question, you'd want your PayPal API calls to take place on the server side as much as possible.
Error: "Hosted Fields payment is already in progress."
I have copied it from this PayPal documentation, and in the SDK URL pass a proper sandbox clientID.
if (paypal.HostedFields.isEligible()) {
paypal.HostedFields.render({
createOrder: function () {return "order-ID";}, // replace order-ID with the order ID
styles: {
'input': {
'font-size': '17px',
'font-family': 'helvetica, tahoma, calibri, sans-serif',
'color': '#3a3a3a'
},
':focus': {
'color': 'black'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: 'card number'
},
cvv: {
selector: '#cvv',
placeholder: 'card security number'
},
expirationDate: {
selector: '#expiration-date',
placeholder: 'mm/yy'
}
}
}).then(function (hf) {
$('#my-sample-form').submit(function (event) {
event.preventDefault();
hf.submit({
// Cardholder Name
cardholderName: document.getElementById('card-holder-name').value,
// Billing Address
billingAddress: {
streetAddress: document.getElementById('card-billing-address-street').value, // address_line_1 - street
extendedAddress: document.getElementById('card-billing-address-unit').value, // address_line_2 - unit
region: document.getElementById('card-billing-address-state').value, // admin_area_1 - state
locality: document.getElementById('card-billing-address-city').value, // admin_area_2 - town / city
postalCode: document.getElementById('card-billing-address-zip').value, // postal_code - postal_code
countryCodeAlpha2: document.getElementById('card-billing-address-country').value // country_code - country
}
});
});
});
}
You need to replace "order-ID" with an actual PayPal Order ID created for this checkout.
There are several ways to obtain one. See https://developer.paypal.com/docs/business/checkout/server-side-api-calls/#server-side-api-calls for how to call the orders API from your server to 'Create Order' and 'Capture Order'. You should use these to create two routes on your server that return only JSON data (no HTML or text)
As for how to fetch and commit this from the JS UI, see https://developer.paypal.com/demo/checkout/#/pattern/server for some demo code.
Alternatively, you could try doing an HTML/JS-only integration (no server) like https://developer.paypal.com/demo/checkout/#/pattern/client
is there a way to automatically submit the form after the user has chosen a payment method with the Braintree Drop-in?
The problem is that the user is asked to choose a payment method, then press Ok, then again Ok, then press the actual Checkout button on my page.
It is a very weird behavior.
Here's the code I use to create the Drop-In.
<script>
var form = document.querySelector('#payment-form');
var nonceInput = document.querySelector('#nonce');
braintree.dropin.create({
authorization: '{{ $client_token }}',
container: '#dropin-container',
paypal: {
flow: 'vault',
currency: 'EUR',
buttonStyle: {
color: 'blue',
shape: 'rect',
size: 'medium'
}
},
card: {
cardholderName: true
}
}, function (err, dropinInstance) {
if (err) {
// Handle any errors that might've occurred when creating Drop-in
console.error(err);
return;
}
form.addEventListener('submit', function (event) {
event.preventDefault();
dropinInstance.requestPaymentMethod(function (err, payload) {
if (err) {
// Handle errors in requesting payment method
return;
}
$.fancybox.open({
src : '#processing-loading',
type : 'inline',
opts : {
toolbar: false,
buttons: false,
smallBtn: false
}
});
// Send payload.nonce to your server
nonceInput.value = payload.nonce;
form.submit();
});
});
});
</script>
I am trying to integrate the express-checkout API with node.js and express. It's my first time using PayPal's API and I am having trouble getting the lightbox to stop spinning and allowing the user to approve and authorize the payment. When the user clicks the checkout button, the payment method is invoked twice (2 payments are created with 2 different ids with a time difference of about 2 mins) and the lightbox pops up but keeps spinning and doesn't prompt the user to do anything. I appreciate any help on this.
My client-side code:
<div id="paypal-button"></div>
<script>
paypal.Button.render({
env: 'sandbox', // Or 'sandbox',
commit: true, // Show a 'Pay Now' button
style: {
color: 'gold',
size: 'small'
},
payment: function() {
/* Make a call to the server to set up the payment */
return paypal.request.post("http://localhost:3000/paypal/create-payment")
.then(function(res) {
return res.id;
})
},
onAuthorize: function(data, actions) {
/*
* Execute the payment here
*/
return paypal.request.post("http://localhost:3000/paypal/execute-payment",
{
paymentID: data.paymentID,
payerID: data.payerID
}).then(function(res) {
// The payment is complete!
// You can now show a confirmation message to the customer
window.alert("PAYMENT COMPLETE!");
});
},
onCancel: function(data, actions) {
/*
* Buyer cancelled the payment
*/
console.log("BUYER CANCELLED!");
},
onError: function(err) {
/*
* An error occurred during the transaction
*/
console.log(err);
}
}, '#paypal-button');
</script>
My server-side code:
// CREATE PAYMENT ROUTE
app.post("/paypal/create-payment", function(req, res){
// CREATE JSON REQUEST
var create_payment_json = {
"intent": "sale",
"redirect_urls":
{
"return_url": "https://localhost:3000/success",
"cancel_url": "https://localhost:3000/cancel"
},
"payer":
{
"payment_method": "paypal"
},
"transactions": [
{
"amount":
{
"total": "",
"currency": "USD",
"details":{
"subtotal": "",
"shipping": "0.00",
"tax": "0.00",
"shipping_discount": "0.00"
}
},
"item_list":
{
"items": []
},
"description": "Test shopping cart transaction."
}]
};
// Change the "total", "subtotal", and "items" array in the json request
create_payment_json["transactions"][0]["amount"]["total"] = cart.totalPrice.toString();
create_payment_json["transactions"][0]["amount"]["details"]["subtotal"] = cart.totalPrice.toString();
// Dummy variable for less typing
var itemsArray = create_payment_json["transactions"][0]["item_list"]["items"];
// 1) Access each puppy in the cart
// 2) Create an object with the following properties:
// quantity, name, price, currency, description, and tax
// 3) push that object into itemsArray
cart["puppies"].forEach(function(puppy){
var dummy = {
"quantity" : "1",
"name" : puppy.name,
"price" : puppy.price.toString(),
"currency" : "USD",
"description" : puppy.description,
"tax" : "0"
};
itemsArray.push(dummy);
});
// Send a Create Payment request to the Payments API
paypal.payment.create(create_payment_json, function (error, payment){
if (error) {
console.log(error);
} else {
console.log(payment);
console.log("==============");
}
});
});
// EXECUTE PAYMENT ROUTE
app.post("/paypal/execute-payment", function(req, res){
var payerId = { payer_id: req.query.PayerID };
var paymentId = req.query.paymentId;
console.log("Payer ID: " + payerId);
console.log("Paymend ID: " + paymentId);
paypal.payment.execute(paymentId, payerId, function(error, payment){
if (error){
console.log(error);
} else {
if(payment.state === "approved"){
console.log(payment);
res.send("SUCCESS");
} else {
console.log("payment not successful");
}
}
});
});
The console.log(payment) in the paypal.payment.create method is run twice. That's how I know that the payment method is invoked twice. I don't know how to solve this. Any help or suggestion is appreciated!
Update: changed return res.paymentId into return res.id, but no luck.