Vue Can Paypal Sandbox Accounts Make Real Transactions on New Website - javascript

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.

Related

How to create Paypal Button in Vue 3 script setup?

The paypal developer docs show how to implement the Paypal Button into Vue.js but I don't understand the code. At this point I'm not even sure if this is vue 2 or vue 3 or angular?? code.
1: import script in parent blade:
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
2: use button in script tag of component?
paypal.Buttons.driver("vue", window.Vue);
3: this is where I get lost, use this in app.js??:
#ng.core.Component({
selector: 'my-app',
template:
<div id="app">
<paypal-buttons [props]="{
createOrder: createOrder,
onApprove: onApprove
}"></paypal-buttons>
</div>
,
})
class AppComponent {
createOrder(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '0.01'
}
}]
});
}
onApprove(data, actions) {
return actions.order.capture();
}
}
#ng.core.NgModule({
imports: [
ng.platformBrowser.BrowserModule,
paypal.Buttons.driver('angular2', ng.core)
],
declarations: [
AppComponent
],
bootstrap: [
AppComponent
]
})
class AppModule {}
ng.platformBrowserDynamic
.platformBrowserDynamic()
.bootstrapModule(AppModule);
Could it be that this isn't even vue code but angular code?
4: and put this in the vue component??:
<div id="container">
<app></app>
</div>
<script>
const PayPalButton = paypal.Buttons.driver("vue", window.Vue);
Vue.component("app", {
// The style prop for the PayPal button should be passed in as `style-object` or `styleObject` to avoid conflict with Vue's `style` reserved prop.
template: `
<paypal-buttons :on-approve="onApprove" :create-order="createOrder" :on-shipping-change="onShippingChange" :on-error="onError" :style-object="style" />
`,
components: {
"paypal-buttons": PayPalButton,
},
computed: {
createOrder: function () {
return (data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
value: "10",
},
},
],
});
}
},
onApprove: function () {
return (data, actions) => {
return actions.order.capture();
}
},
onShippingChange: function () {
return (data, actions) => {
if (data.shipping_address.country_code !== 'US') {
return actions.reject();
}
return actions.resolve();
}
},
onError: function () {
return (err) => {
console.error(err);
window.location.href = "/your-error-page-here";
}
},
style: function () {
return {
shape: 'pill',
color: 'gold',
layout: 'horizontal',
label: 'paypal',
tagline: false
}
},
},
});
const vm = new Vue({
el: "#container",
});
</script>
My question is, how would I create a simple paypal button in Vue 3's script setup? The paypal cdn is imported in the parent blade file.
Something like:
<script setup>
import {onMounted} from "vue";
onMounted(() => {
//create component from -> paypal.Buttons.driver("vue", window.Vue);
})
</script>
<template>
<div id="checkout" class="checkout">
<paypal-buttons></paypal-buttons>
</div>
</template>
I would recommend the following implementation:
Install official paypal-js npm package: npm install #paypal/paypal-js
Then you can write your PaypalButtons Component as follows:
<script setup>
import {Inertia} from '#inertiajs/inertia';
import {loadScript} from '#paypal/paypal-js';
import {onMounted} from 'vue';
const props = defineProps({
// Some kind of reference if you like
reference: Object
});
onMounted(async() => {
try {
const paypal = await loadScript({
'client-id': <your-paypal-client-id>
});
await paypal.Buttons({
createOrder: function() {
function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
// e.g reference.price
value: '<your-price>',
},
}],
});
},
onApprove: function(data) {
return actions.order.capture().then(function(orderData) {
// Successful capture!
// e.g. Inertia.post(route('order.update', reference.orderId)
});
},
style: {
// Adapt to your needs
layout: 'vertical',
color: 'gold',
shape: 'rect',
label: 'paypal',
},
// The following is optional and you can
// limit the buttons to those you want to
// provide
fundingSource: paypal.FUNDING.PAYPAL,
}).render('#paypal-button-container');
} catch (error) {
// Add proper error handling
console.error(error);
}
});
</script>
<template>
<div id="paypal-button-container"></div>
</template>
Now use it as:
<PaypalButtons :reference="reference" />
Paypal documentation is a huge mess. The server integration seems to work like so:
if you're using laravel as backend, import this into app.blade.php/welcome.blade.php file:
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
and then your vue component can look like this:
<script setup>
import {onMounted} from "vue";
onMounted(() => {
paypal.Buttons({
// Call your server to set up the transaction
createOrder: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order/create/', {
method: 'post'
}).then(function(res) {
return res.json();
}).then(function(orderData) {
return orderData.id;
});
},
// Call your server to finalize the transaction
onApprove: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order/' + data.orderID + '/capture/', {
method: 'post'
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// Three cases to handle:
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
// (2) Other non-recoverable errors -> Show a failure message
// (3) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart(); // Recoverable state, per:
// https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
}
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); // Show a failure message (try to avoid alerts in production environments)
}
// Successful capture! For demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
var transaction = orderData.purchase_units[0].payments.captures[0];
alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');
// Replace the above to 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>';
// Or go to another URL: actions.redirect('thank_you.html');
});
}
}).render('#paypal-button-container');
})
</script>
<template>
<div id="checkout" class="checkout">
<div id="paypal-button-container"></div>
</div>
</template>
Which payment methods are displayed is determined automatically and depends on your IP (???). You can hide payment methods by manipulating the script import like so:
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&disable-funding=card,giropay,sepa,sofort"></script>

How to get Paypal Checkout to work with Vue.JS 3

I am trying to make Paypal Checkout work with Vue.JS 3 (using the loader)
Right now I got this far:
setPaypal() {
const script = document.createElement('script');
script.src = 'https://www.paypal.com/sdk/js?client-id=AdlvqGHWrrwVpGXreZuf5VHBXjIeUWGLHBJmDzbI44Ib2w1MMN7P-UJysCHFb_W7BWTvpz0ofji0SiYB';
document.body.appendChild(script);
script.addEventListener('load', this.setLoaded())
}
This function is called in the mounted(): and inserts the script tag in my page.
setLoaded() {
window.paypal.Buttons({
createOrder: (actions) => {
return actions.order.create({
purchase_units: [
{
description: this.prestation.courtedescription,
amount: {
currency_code: "EUR",
value: this.total
}
}
]
});
},
onApprove: async () => {
this.paidFor = true;
this.loading = false;
},
onError: err => {
console.log(err)
}
})
.render(this.$refs.paypal)
}
This is the setLoaded() function called when the script is loaded.
Well obviously window.paypal is undefined
I tried using the official docs and same shit, they ask you to
const PayPalButton = paypal.Buttons.driver("vue", window.Vue);
But hey, paypal is not defined
For reference, this is the official docs
Add the SDK <script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
Vue integration
<div id="container">
<app></app>
</div>
<script>
const PayPalButton = paypal.Buttons.driver("vue", window.Vue);
Vue.component("app", {
template: `
<paypal-buttons :on-approve="onApprove" :create-order="createOrder" />
`,
components: {
"paypal-buttons": PayPalButton,
},
computed: {
createOrder: function () {
return (data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
value: "10",
},
},
],
});
}
},
onApprove: function () {
return (data, actions) => {
return actions.order.capture();
}
},
},
});
const vm = new Vue({
el: "#container",
});
</script>
Instead of using this in your setPaypal() function
script.addEventListener('load', this.setLoaded())
Use this
script.addEventListener('load', () => this.setLoaded())

Chrome extension - button listener on notification executes multiple times

I am writing a chrome extension that makes requests to an API and I have noticed that after I create a notification from background script using chrome's notification API, the listeners on the buttons from the notification are executed multiple times. on the first run only once and then increasing. I figured that the listeners just add up on the page but I couldn't find a way to sort of refresh the background page.
This is the function that creates the notification and it's listeners.
var myNotificationID
const displayNotification=(userEmail, password, website,username) =>{
chrome.notifications.create("", {
type: "basic",
iconUrl: "./icon128.png",
title: "PERMISSION",
requireInteraction: true,
message: "question",
buttons: [{
title: "YES",
}, {
title: "NO",
}]
}, function(id) {
myNotificationID = id;
})
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (notifId === myNotificationID) {
if (btnIdx === 0) {
console.log('inserting')
try{
fetch (`http://localhost:8080/users/${userEmail}/accounts`,{
})
}catch(err){
}
} else if (btnIdx === 1) {
console.log('clearing')
chrome.notifications.clear(myNotificationID)
}
}
});
}
And this is where the function is called
chrome.runtime.onMessage.addListener((message, sender, response)=>{
if(message.message === 'showNotification'){
console.log('received insert')
displayNotification(message.userEmail,message.password, message.currentSite,message.username)
response({status:"received"})
}
})
the fetch within the listener is executed multiple times but the log from the onMessage listener is only displayed once, so the listener is the problem here.
I tried chrome.notifications.onButtonClicked.removeListener(), but as i mentioned there was no success.
Are there any other ways in which i could clean the listeners from the background script once they are used?
Using a notification store:
const notificationsByID = {};
chrome.notifications.onButtonClicked.addListener((notifId, btnIdx) => {
// Avoid access to the notification if not registered by displayNotification
if (!notificationsByID[ notifId ]) { return null; }
if (btnIdx === 0) {
console.log('inserting')
try{
fetch (`http://localhost:8080/users/${ notificationsByID[ notifId ].userEmail }/accounts`,{ /**/ });
}catch(err){
console.log(err);
}
delete notificationsByID[ notifId ]; // Cleanup
} else if (btnIdx === 1) {
console.log('clearing')
chrome.notifications.clear(myNotificationID);
delete notificationsByID[ notifId ]; // Cleanup
}
});
chrome.notifications.onClosed.addListener((notifId) => {
if (notificationsByID[ notifId ]) { delete notificationsByID[ notifId ]; }
});
const displayNotification=(userEmail, password, website,username) =>{
chrome.notifications.create("", {
type: "basic",
iconUrl: "./icon128.png",
title: "PERMISSION",
requireInteraction: true,
message: "question",
buttons: [{ title: "YES", }, { title: "NO", }]
}, function(id) {
// Insertion
notificationsByID[ id ] = { userEmail, password, website,username };
})
}

Integration of Amazon Payments with Javascript and PHP - PaymentPlanNotSet

Currently I try to integrate amazon payment.
I want to display the button, created with the function:
OffAmazonPayments.Button("AmazonPayButton", myAmznMerchantID
and after the User has logged in, I want to display the AdressBook Widget and the Payment Widget on the same Page.
The Button and the Widgets are displayed correctly, but when I try to confirm the Payment, I'm getting the Error-Constrains Message:
PaymentPlanNotSet The buyer has not been able to select a Payment
method for the given Order Reference.
But the Payment was selected.
I hope you can help me, to find my failure in this Javascript code:
window.onAmazonLoginReady = function () {
amazon.Login.setClientId(myAmznClientID);
};
window.onAmazonPaymentsReady = function() {
var __accessToken = 0;
var __orderReferenceId = 0;
show_amazon_Button();
function show_amazon_Button() {
OffAmazonPayments.Button("AmazonPayButton", ibuiAmazonPaymentsInfos.ibAmznMerchantID, {
type: "PwA",
color: "Gold",
size: "small", // "medium",
language: "de-DE",
authorization: function () {
loginOptions = { scope: "profile:user_id", popup: true };
authRequest = amazon.Login.authorize(loginOptions, function(response) {
if (response.error) {
//show Error
return;
} else {
__accessToken = response.access_token;
show_Adress_Widget();
}
});
},
onError: function(error) {
//handleError
}
});
}
function show_Adress_Widget() {
new OffAmazonPayments.Widgets.AddressBook({
sellerId: ibuiAmazonPaymentsInfos.ibAmznMerchantID,
onOrderReferenceCreate: function (orderReference) {
__orderReferenceId = orderReference.getAmazonOrderReferenceId();
//do Stuff
},
onAddressSelect: function (orderReference) {
show_Amazon_Wallet();
},
design: {
designMode: 'responsive'
},
onError: function (error) {
//handle Error
}
}).bind("readOnlyAddressBookWidgetDiv");
}
function show_Amazon_Wallet() {
new OffAmazonPayments.Widgets.Wallet({
sellerId: myAmznMerchantID,
onOrderReferenceCreate: function(orderReference) {
//do Stuff
},
design: {
designMode: 'responsive'
},
onPaymentSelect: function(orderReference) {
//activate buy button
},
onError: function(error) {
//handle error
}
}).bind('AmazonWalletWidgetDiv');
}
} //onAmazonPaymentsReady
In PHP I create the OrderReference over:
$params = array(
'order_reference_id' => $orderReferenceId,
'amount' => $amount,
'seller_order_id' => $buchungsKopf->getBuchung_nr(),
);
$responseObject = $client->setOrderReferenceDetails($params);
And even if I had selected a payment method before, I'm getting the "PaymentPlanNotSet" in the responseObject.
Same error, when I try to confirm the orderReference
$responseObject2 = $client->confirmOrderReference($params);
Before I had integrate the AdressWidget, I was able to do the payment.
Can you see what I'm doing wrong?
It seems I have found my failure.
When I want to display both Widgets (Adress and Wallet) on the same page, then I can not use the onOrderReferenceCreate-Method in the OffAmazonPayments.Widget.Wallet.
It seems like then it create a new order reference wich is not the same as the orderreference created by the AdressBook Widget.
Now I have delete this part of the Wallet Widget and everything seems to work fine.

Firebase charge function not being received by Stripe

I'm working with charging credit cards on an ionic application. If I check the Stripe website, only the token is created successfully. There is no event for the charge. When I check Firebase everything seems to be working (previously I had error message "An error occurred with our connection to Stripe" which was eliminated by upgrading to paid version Blaze).
I've structured the following code so you can see the sequence of events.
Here is the sequence of events:
1) Here I get the token and pass to payByStripe function:
checkOut() {
let alert = this.alertCtrl.create({
title: 'card information',
cssClass:'alert-css',
inputs: [{
name: 'cardNumber',
placeholder: 'card number',
},
{
name: 'expMonth',
placeholder: 'expMonth',
},
{
name: 'expYear',
placeholder: 'expYear',
},
{
name: 'cvc',
placeholder: 'cvc',
}],
buttons: [{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
}
},
{
text: 'PAY',
handler: data => {
this.stripe.setPublishableKey('pk_test_abcdef1BC');
let card = {
number: data.cardNumber,
expMonth: data.expMonth,
expYear: data.expYear,
cvc: data.cvc
};
this.stripe.createCardToken(card)
.then(token => {
this.goodsData.payByStripe(this.totalMoniesPlusTaxAndCharge,this.userEmail,token);
let alert = this.alertCtrl.create({
title: 'Charged',
cssClass:'alert-css',
subTitle: 'Successful Charge!',
buttons: ['Dismiss']
});
alert.present();
}, error => {
this.loading.dismiss();
let alert = this.alertCtrl.create({
title: 'ERROR',
cssClass:'alert-css',
subTitle: JSON.stringify(error),
buttons: ['Dismiss']
});
alert.present();
})
.catch(error => console.log(JSON.stringify(error)) );
}
}]
});
alert.present();
}
2) Here, I push the charge to Firebase, where cloud functions will handle it:
payByStripe(amount,email,token): firebase.database.Reference {
return firebase.database().ref('/stripe_customers/charges/').push({
amount:amount,
email:email,
token:token
});
}
3) Here is what the cloud functions are doing:
const functions = require('firebase-functions'),
admin = require('firebase-admin'),
logging = require('#google-cloud/logging')();
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')(functions.config().stripe.token),
currency = functions.config().stripe.currency || 'USD';
// [START chargecustomer]
// Charge the Stripe customer whenever an amount is written to the Realtime database
exports.createStripeCharge = functions.database.ref('/stripe_customers/charges/').onWrite(event => {
const val = event.data.val();
// This onWrite will trigger whenever anything is written to the path, so
// noop if the charge was deleted, errored out, or the Stripe API returned a result (id exists)
if (val === null || val.id || val.error) return null;
// Look up the Stripe customer id written in createStripeCustomer
// Create a charge using the pushId as the idempotency key, protecting against double charges
const amount = val.amount;
const email = val.email;
const token = val.token;
stripe.charges.create({
amount: amount,
currency: "usd",
source: token,
description: "Charge for " + email
}).then(response => {
// If the result is successful, write it back to the database
return event.data.adminRef.set(response);
}, error => {
// We want to capture errors and render them in a user-friendly way, while
// still logging an exception with Stackdriver
return event.data.adminRef.child('error').set(userFacingMessage(error)).then(() => {
return reportError(error, {user: event.params.userId});
});
});
});
// [END chargecustomer]]
I'm pretty sure that's a Firebase-specific error, so if the cause isn't clear, you may want to reach out to them - though someone else with more Firebase experience may have a more useful answer for you!

Categories

Resources