Paypal Express Checkout: Recurring payments on specific date - javascript

I am attempting to setup our website to accept recurring payments on a specific date (£5 on 1st June every year) regardless of when the user initially signs up (except for the month of May, then thier first rebill will be on 1st June the following year)
My searches so far have yielded that Express Checkout (checkout.js) is probably my best option.
I have managed to, in sandbox mode, take the initial payment of £5, but can't find any documentation on how to setup the recurring payment.
Code below
paypal.Button.render(
{
env: "sandbox", // 'production' Or 'sandbox',
// Pass the client ids to use to create your transaction on sandbox and production environments
client: {
sandbox:
[REDACTED], // from https://developer.paypal.com/developer/applications/
production:
[REDACTED] // from https://developer.paypal.com/developer/applications/
},
// Pass the payment details for your transaction
// See https://developer.paypal.com/docs/api/payments/#payment_create for the expected json parameters
payment: function(data, actions) {
return actions.payment.create({
transactions: [
{
amount: {
total: "5.00",
currency: "GBP"
}
}
]
});
},
// Display a "Pay Now" button rather than a "Continue" button
commit: true,
// Pass a function to be called when the customer completes the payment
onAuthorize: function(data, actions) {
console.log(data);
console.log(actions);
return actions.payment.execute().then(function(response) {
console.log("The payment was completed!");
});
},
// Pass a function to be called when the customer cancels the payment
onCancel: function(data) {
console.log("The payment was cancelled!");
}
},
"#paypal-button"
);

Related

Paypal - Split payment and send it to different PayPal account

My goal is to get 5% of the amount and send it to Company PayPal account, and the other 95% will send directly to the Paypal of the other user. How can I do it in PayPal Code?
Here is my PayPal code.
paypal.Button.render({
style: {
size: 'responsive',
color: 'black'
},
env: 'sandbox', // 'sandbox' Or 'production',
client: {
sandbox: 'MyClientID',
production: ''
},
locale: 'en_US',
commit: true, // Show a 'Pay Now' button
payment: function(data, actions) {
// Set up the payment here
return actions.payment.create({
payment: {
transactions: [{
amount: { total: '1.00', currency: 'USD' }
}]
}
});
},
onAuthorize: function(data, actions) {
// Execute the payment here
return actions.payment.execute().then(function(payment) {
console.log(payment);
});
}
}, '#paypal-button');
Please help me.. Thank you.
No it's not possible with just a Paypal button. Paypal has its own way to split the money to whichever account you want to set it to and you'll need to use the Payouts API.
Note: It used to be "Adaptive Payments" but they (Paypal) stopped allowing new integrations.
According to the documentation: https://developer.paypal.com/docs/api/payments.payouts-batch/v1/
Use the Payouts API to make PayPal payments to multiple PayPal
accounts in a single API call. The Payouts API is a fast, convenient
way to send commissions, rebates, rewards, and general disbursements.
Please note that you'll need a paypal business account to be elligible for this: https://developer.paypal.com/docs/payouts/integrate/prerequisites/#

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!

paypal checkout using client integration

I have the following sample code from the paypal dev documentation.
<div id="paypal-button-container"></div>
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
// Render the PayPal button
paypal.Button.render({
// Set your environment
env: 'sandbox', // sandbox | production
// Specify the style of the button
style: {
layout: 'vertical', // horizontal | vertical
size: 'medium', // medium | large | responsive
shape: 'rect', // pill | rect
color: 'gold' // gold | blue | silver | white | black
},
// Specify allowed and disallowed funding sources
//
// Options:
// - paypal.FUNDING.CARD
// - paypal.FUNDING.CREDIT
// - paypal.FUNDING.ELV
funding: {
allowed: [
paypal.FUNDING.CARD,
paypal.FUNDING.CREDIT
],
disallowed: []
},
// Enable Pay Now checkout flow (optional)
commit: true,
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
client: {
sandbox: 'AZDxjDScFpQtjWTOUtWKbyN_bDt4OgqaF4eYXlewfBP4-8aqX3PiV8e1GWU6liB2CUXlkA59kJXE7M6R',
production: '<insert production client id>'
},
payment: function (data, actions) {
return actions.payment.create({
payment: {
transactions: [
{
amount: {
total: '0.01',
currency: 'USD'
}
}
]
}
});
},
onAuthorize: function (data, actions) {
return actions.payment.execute()
.then(function () {
window.alert('Payment Complete!');
});
}
}, '#paypal-button-container');
</script>
I've replaced the sandbox client ID with my own ID. When I double click on the HTMl file and open it locally on my web browser, something weird happens. When I click on the checkout box and enter my sandbox buyer's credentials, the buyer's bank account gets deducted. However, when I log onto my sandbox facilitator, it's bank account doesn't get updated.
Could someone please help me out? Thanks!!

Customizing Paypal Checkout Variables

Hi i have been searching around with how I can customize the paypal variable for checkoutJS more specifically with this function here
payment: function (data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: 'cost', currency: 'PHP' }
}
]
}
});
},
I need to be able to edit the 'cost' based on a text of my div.
i tried doing this ( forgive me if this is stupid ) :
var cost = document.getElementById('cost').InnerText;
payment: function (data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: cost, currency: 'PHP' }
}
]
}
});
},
Now, when i click the "Buy now" button a popup window appears with a spinner then closes.
I am trying to this in ASP MVC if it is of any relevance.
Help would be very much appreciated!

Remove unverified Meteor users after certain time period?

I'm working on a Meteor app and I want to rid the app of the antiquated "Create New Account" then "Check Your Email to Verify Account" workflow. I want users to sign up with an email (not a username) and immediately have some access to the app, a verification email will fire, and then they can verify at a later time to get full access. So I would be calling Accounts.createUser immediately and always (as long as their email isn't already taken.)
How would I go about "taking out the garbage" of any email-based accounts that get created but are never verified? Like if I wanted to delete an unverified account after 3 days for example?
The only way I can think of is to do a really long Meteor.setTimeout command in the Accounts.onCreateUser hook that would check if the accounts email is verified after three days (which is 259,200,000 ms BTW). Is this practical? Will it work? Is there another method in Meteor to do something like this? That isn't dependent on user actions. I don't want to do this when the user logs in because a user could create an account with a bad email and then never log in again, but a future user with that email would then be locked out.
Does Meteor have any type of "server rules" that would fire every so often to run checks? Like setup some kind of nightly maintenance function/routine? Also, is it possible to remove a User like this? I was reading another article that said something about not being able to remove users through the API. I definitely need to be able to do that because the whole point is to make that email/account available to a user that actually owns that email.
If I have to I can go to the "force verification" methodology, but I see other sites doing the above and I like it much better. It's also way slicker on mobile.
EDIT: I was just looking at the Meteor docs and sending a "verification email" requires a userId which means you have to create a user no matter what - Accounts.sendVerificationEmail(userId, [email]). So I guess no matter what a user with a bad email could get created. So it would be nice to know how to do the above.
You can use a simple cron with Meteor.setInterval.
I wouldn't advise using Meteor.setTimeout with the onCreateUser hook. This is because if you're server is restarted/has a crash/you update the code within this 3 day period the snippet won't run.
Server Side Code:
Meteor.setInterval(function() {
// new Date must always be new Date()
var three_days_ago = new Date(new Date().getTime() - (3600000*72))
Meteor.users.find({
createdAt: {
$lte: three_days_ago //Users created less than 3 days ago
},
'emails.0.verified': false
}).forEach(function(user) {
//Do action with 'user' that has not verified email for 3 days
});
}, 3600000);
The above code runs every hour, checking for users that were created more than 3 days ago (72 hours) that have not yet verified their first email address.
To mix and update the old answers (#Akshat wrote new Date(new Date.getTime() - (3600000*72)) but it's new Date(new Date().getTime() - (3600000*72)) ), in a cron job way every day
Install synced-cron
meteor add percolate:synced-cron
On server, in a cron.js
import { SyncedCron } from 'meteor/percolate:synced-cron';
import { deleteUnverifiedUsers } from './delete-unverifiedUsers.js';
SyncedCron.config({ log: false, utc: true });
SyncedCron.add({
name: 'Check verified Users',
schedule(parser) {
//return parser.text('every 10 seconds');
//return parser.text('every 1 hour');
return parser.text('every 24 hours');
},
job() {
deleteUnverifiedUsers();
}
});
SyncedCron.start();
On server in the task file (here delete-unverifiedUsers.js)
import { Meteor } from 'meteor/meteor';
// Set since variable in milliseconds*hours : ex 1h = 3600000*1
var one_day_ago = new Date(new Date().getTime() - (3600000*24))
Meteor.users.find({
// condition #1: users created since variable ago
createdAt: {
$lte: one_day_ago,
},
// condition #2: who have not verified their mail
'emails.0.verified': false
}).forEach(function(user) {
// Delete the users who match the 2 conditions
return Meteor.users.remove({_id: user._id})
});
Use percolatestudio:synced-cron:
meteor add percolatestudio:synced-cron
Then in your Javascript on the server:
if (Meteor.isServer) {
Meteor.startup(function () {
SyncedCron.add({
name: 'Remove unverified users',
schedule: function(parser) {
// parser is a later.parse object
return parser.text('every Wednesday at 12am');
},
job: function() {
//TODO: implement RemoveUnverifiedUsers function
var numUsersRemoved = RemoveUnverifiedUsers();
return numUsersRemoved;
}
});
// start the cron daemon
SyncedCron.start();
}
}
Edit #1:
The Meteor user will have an email object with verified:false in the Meteor.users collection. This part of the meteor docs provides the following example:
{
_id: "bbca5d6a-2156-41c4-89da-0329e8c99a4f", // Meteor.userId()
username: "cool_kid_13", // unique name
emails: [
// each email address can only belong to one user.
{ address: "cool#example.com", verified: true },
{ address: "another#different.com", verified: false }
],
createdAt: Wed Aug 21 2013 15:16:52 GMT-0700 (PDT),
profile: {
// The profile is writable by the user by default.
name: "Joe Schmoe"
},
services: {
facebook: {
id: "709050", // facebook id
accessToken: "AAACCgdX7G2...AbV9AZDZD"
},
resume: {
loginTokens: [
{ token: "97e8c205-c7e4-47c9-9bea-8e2ccc0694cd",
when: 1349761684048 }
]
}
}
}

Categories

Resources