New to meteor and stripes API I am trying to apply this coupon code using Meteor and stripe.This is for a one time payment with a coupon. However the handleCharge method fires before the process payment method. And I want the Stripe.coupons.retrieve to return a result first before the payment is processed.
Server Method
Meteor.methods({
processPayment( charge, coupon ) {
Stripe.coupons.retrieve(
coupon,
function(err, result) {
if( result ) {
charge.amount = parseInt(charge.amount) - parseInt( charge.amount * coupon.percent_off );
}
}
);
let handleCharge = Meteor.wrapAsync( Stripe.charges.create, Stripe.charges ),
payment = handleCharge( charge );
return payment;
}
});
I've also tried to return a result before the coupon is passed into the processPayment. Then when i try to console.log the result it is always undefined.
checkForCoupon( couponCode ) {
let result = false;
Stripe.coupons.retrieve(
couponCode,
function(err, coupon) {
if( err ) {
result = false;
} else {
result = true;
}
}
);
return result;
}
Meteor.call( 'checkForCoupon', coupon, ( error, response ) => {
if ( error ) {
console.log( error );
} else {
console.log( "Success");
}
});
Any help would be greatly appreciated.
Ok here's a thing, the argument for coupon key in stripe api takes a string which looks like you already have because you are passing that in coupons.retrieve api, so what you'll get from this api is coupon object which is no use to you. So usually in Stripe we already have coupon id before creating subscription which gets passed in Stripe API for discount.
But as you said you are having problem in getting response before running another method, so here I can suggest you to use Async.runSync of meteor.
And another thing is that you can't use coupon in charge.create api, its for subscriptions. So here's how my approach would be with subscription:
Here I'm retreiving coupons object from coupon_id and and then hitting subscriptions API.
On Client:
var data = {
source: "source",
plan: "plan"
}
Meteor.call('processPayment', data, function(err, res) {
if(err)
return;
console.log("Subscription added with coupon");
});
On Server:
Meteor.methods({
var coupon;
'processPayment': function(data) {
check( data, {
source: String,
plan: String
});
Async.runSync(function(done) {
var coupon = Stripe.coupons.retrieve("coupon_id", function(err, coupon) {
if(err) {
return done(null); //done is callback
}
return done(null, coupon);
});
});
//this code will only run when coupon async block is completed
if(coupon !== null) {
data.coupon = coupon.id;
}
var subscription = Async.runSync(function(done) {
Stripe.subscriptions.create(data, function(err, subscription) {
if(err) {
console.log(err);
return done(null, err);
}
return done(null, subscription);
}
);
});
return subscription;
}
});
Hope this helps you and feel free to ask anything in comments, I'll be more than happy to answer.
Related
I am trying to make a fetch in react.js using backend node.js api url which then further makes a post api call within the server to another route using another url.
How am i supposed to do that?
Take a look at the code below:
From the frontend "/confirm" api will be called using fetch.
app.post("/save-info",(req,res)=>{
//Does some more stuff and returns a
response to the confirm api.
}
app.post("/confirm", (req,res)=>{
//Does some stuff
//Makes another call inside this api
to the "/save-info" route
}
Updated Query
Guys, please take a look at the code below
async function signUp(info) {
const {
firstName,
lastName,
address,
email,
phoneNumber,
password,
city,
postal_code,
} = info;
console.log("only info: ", phoneNumber);
const queryInsertNewUser = `INSERT INTO public."Users"(
"First_Name", "Email", "Mobile", "Address", "User_Type", "Last_Name", "password", "city","postal_code")
VALUES ('${firstName}', '${email}', '${phoneNumber}', '${address}', 'Customer', '${lastName}', '${password}','${city}','${postal_code}')
RETURNING user_id;`;
// return { email: "kalo", id: "23" };
client.query(queryInsertNewUser, (err, result) => {
if (!err) {
if (result.rowCount == 1) {
console.log("User registered.");
return {
status: "Success",
msg: "User Registered Successfully",
user_id: result.rows[0].user_id,
};
} else {
console.log("Not Registered.");
return {
status: "Error",
msg: "Could not register user. Call Developer.",
};
}
} else {
console.log(err);
}
});
}
app.post("/signup", async(req, res) => {
const { email } = req.body;
const data = await signUp(req.body);
console.log(data);
});
data is printing undefined. Still it does not work
You don't need to call your route again. Just create an function and call it.
const saveInfo = ()=>{
// do wathever you want here
return "some stuff done"
}
app.post("/save-info",(req,res)=>{
// you probabbly don't need this route.
}
app.post("/confirm", (req,res)=>{
//Does some stuff
const data = saveInfo()
return res.send({success:true, done})
}
please suggest me how to make a selection from database comparing the ID in the collection with each element of the array?
Here is the code that unfortunately returns an empty array:
index(req, res) {
Room.find({_id: req.user.rooms.forEach((item)=>{
return item;
})
})
.then((rooms) => {
console.log(rooms)
res.send(rooms)
}
)
.catch(err => res.status(400).json(err));
}
req.user.rooms - each item of this array is ID, that I want to compare with what is in the collection Room.
It's pretty straight-forward in their docs for how to query items in a list.
Your code should look something like this:
index(req, res) {
// Additional validation should be done to make sure that req.user.rooms
// is an array with length > 0. I'll leave that for you to do.
const rooms = req.user.rooms;
Room.find({ _id: rooms})
.then((rooms) => {
console.log(rooms)
res.send(rooms)
})
.catch(err => res.status(400).json(err));
}
Going beyond that, you should really not be doing DB queries from your controller; it's not a good architectural practice This is how it could look in your node service
roomController.js
const RoomService = require("/path/to/services/directory"); // Let services contain all business logic. Don't give them anything related to your web server framework
async index(req, res) {
// Additional validation should be done to make sure that req.user.rooms
// is an array with length > 0. I'll leave that for you to do.
try {
const rooms = await RoomService.retrieveById(req.user.rooms);
res.send( { success: true, data: rooms } ); // We send back the result when we get one
} catch ( err ) {
// We respond to the client with our error, ideally you'll log it too
res.status( err.statusCode ).send( { success: false, error: err } );
}
}
RoomService.js
const Room = require("/path/to/your/model");
module.exports = {
retrieveById: async function(ids) {
try {
return await Room.find({ _id: ids}); // Typically this would be abstracted to a DB layer. but putting it here for brevity
} catch( err ) {
throw new Error( err ); // This is caught in our controller, which we send to client
}
}
};
I have an App using Parse.com as a backend and an external site that acts as my payment gateway. Upon receiving the customer/subscription webhook data from Stripe I wish to lookup the users email so I can then run a Cloud Code function and change their user status to 'paid'
My webhook receiver is:
Parse.Cloud.define("update_user", function(request, response) {
var data = request.params["data"]
var customer = data.object.customer;
response.success'Working' + request);
});
And I am able to get an email back from stripe from the customer ID using:
Parse.Cloud.define("pay", function(request, response) {
Stripe.initialize(STRIPE_SECRET_KEY);
console.log(JSON.stringify(request.params));
Stripe.Customers.retrieve(
customerId, {
success:function(results) {
console.log(results["email"]);
// alert(results["email"]);
response.success(results);
},
error:function(error) {
response.error("Error:" +error);
}
}
);
});
I need help turning this into a complete function that is run on receipt of every webhook from Stripe. I am also struggling with options for fallback if this does not work for whatever reason.
EDIT
Taking parts of the first answer and I now have:
Parse.Cloud.define("update_user", function(request, response) {
Stripe.initialize(STRIPE_SECRET_KEY);
var data = request.params["data"]
var customerId = data.object.customer;
get_stripe_customer(customerId, 100).then(function(stripeResponse) {
response.success(stripeResponse);
}, function(error) {
response.error(error);
});
});
function get_stripe_customer (customerId) {
Stripe.initialize(STRIPE_SECRET_KEY);
return Stripe.Customers.retrieve(
customerId, {
success:function(results) {
console.log(results["email"]);
},
error:function(error) {
}
}
);
};
My knowledge is really falling down on the Promise side of things and also the callback (success:, error, request response) etc further reading would be appreciated.
This is now working
Out of interest I did this:
Parse.Cloud.define("update_user", function(request, response) {
var data = request.params["data"]
var customerId = data.object.customer;
get_stripe_customer(customerId, 100).then(function(stripeResponse) {
return set_user_status(username, stripeResponse);
}).then(function(username) {
response.success(username);
}, function(error) {
response.error(error);
});
});
function get_stripe_customer (customerId) {
Stripe.initialize(STRIPE_SECRET_KEY);
return Stripe.Customers.retrieve(
customerId, {
success:function(results) {
// console.log(results["email"]);
},
error:function(error) {
}
}
);
};
function set_user_status(stripeResponse) {
Parse.Cloud.useMasterKey();
var emailquery = new Parse.Query(Parse.User);
emailquery.equalTo("username", stripeResponse['email']); // find all the women
return emailquery.first({
success: function(results) {
alert('running set_user_status success');
var user = results;
user.set("tier", "paid");
user.save();
},
error:function(error) {
console.log('error finding user');
}
});
};
open to improvements...
EDIT - I (#danh) cleaned it up a bit. A few notes:
used promises throughout. much easier to read and handle errors
get_stripe_customer requires only one param (that 100 was my idea to charge $100)
set_user_status appears to need only user email as param, which apparently is in the stripeResponse
set_user_status returns a promise to save the user. that will be fulfilled with the user object, not the username
be sure you're clear on how to identify the user. stripe apparently provides email address, but in your user query (in set_user_status) you compare email to "username". some systems set username == email. make sure yours does or change that query.
Parse.Cloud.define("update_user", function(request, response) {
var data = request.params["data"]
var customerId = data.object.customer;
get_stripe_customer(customerId).then(function(stripeResponse) {
var email = stripeResponse.email;
return set_user_status(email);
}).then(function(user) {
response.success(user);
}, function(error) {
response.error(error);
});
});
function get_stripe_customer(customerId) {
Stripe.initialize(STRIPE_SECRET_KEY);
return Stripe.Customers.retrieve(customerId).then(function(results) {
// console.log(results["email"]);
return results;
});
};
function set_user_status(email) {
Parse.Cloud.useMasterKey();
var emailquery = new Parse.Query(Parse.User);
emailquery.equalTo("username", email); // find all the women
return emailquery.first().then(function(user) {
user.set("tier", "paid");
return user.save();
}, function(error) {
console.log('error finding user ' + error.message);
return error;
});
}
Did a quick skim of the docs pertaining to stripe, and it looks like the steps are: (1) make a stripe REST-api call from your client side to get a token, (2) pass that token to a cloud function, (3) call stripe from the parse cloud to finish paying. I understand that you'd like to include a (4) fourth step wherein the transaction is recorded in the data for the paying user.
From the client (assuming a JS client):
var token = // we've retrieved this from Stripe's REST api
Parse.Cloud.run("pay", { stripeToken: token }).then(function(result) {
// success
}, function(error) {
// error
});
On the server:
Parse.Cloud.define("pay", function(request, response) {
var user = request.user;
var stripeToken = request.params.stripeToken;
payStripeWithToken(stripeToken, 100).then(function(stripeResponse) {
return updateUserWithStripeResult(user, stripeResponse);
}).then(function(user) {
response.success(user);
}, function(error) {
response.error(error);
});
});
Now we need only to build promise-returning functions called payStripeWithToken and updateUserWithStripeResult.
// return a promise to pay stripe per their api
function payStripeWithToken(stripeToken, dollarAmt) {
Stripe.initialize(STRIPE_SECRET_KEY); // didn't see this in the docs, borrowed from your code
return Stripe.Charges.create({
amount: dollarAmt * 10, // expressed in cents
currency: "usd",
card: stripeToken //the token id should be sent from the client
});
// caller does the success/error handling
}
// return a promise to update user with stripeResponse
function updateUserWithStripeResult(user, stripeResponse) {
var transactionId = // dig this out of the stripeResponse if you need it
user.set("paid", true);
user.set("transactionId", transactionId);
return user.save();
}
For some reason that I cannot seem to wrap my brain around, whenever I send an Object over the network, its parameters change from when I send the Object over the network from the server to when I read it back on the client.
Here's the scenario:
I'm testing an API to delete your user account from the database. You send over your authToken and username parameters in a specially formatted Object, the server queries the database, and if found, your user account is deleted. When everything works perfectly, your account, the server sends this string back to you:
{ header: { type: 'success' }, body: {} }
That's known as a plain SuccessEnvelope. However, when I read the returned string from the server, I get this:
{ header: { type: 'error' }, body: {} }
Now, it seems that the type parameter is being changed somewhere, but I have no idea where! Below you'll find the relevant code which handles all of these requests:
server.js
server = net.createServer(function(socket) {
socket.on("data", function(data) {
try {
// Accept Envelope from client
var input = new Envelope(data.toString());
if (input.verify()) { // Make sure client Envelope has correct data
switch (input.header.type) { // Route commands based on Envelope "type"
case "user":
userHandler.parseEnvelope(input, function(err, res) {
if (err) {
socket.write(errors.parseError(err).toString());
} else {
socket.write(res.toString());
}
});
break;
default:
socket.write(new Envelope().toString());
break;
}
} else {
socket.write(errors.parseError(
new errors.MissingHeaderDataError()).toString());
}
} catch (err) {
socket.write(errors.parseError(err).toString());
}
});
});
user-handler.js
// removing some of the unnecessary stuff
case "delete":
// Make sure user provided all necessary information.
if (!header.token || !body.username) {
return callback(new errors.MissingEnvelopeDataError("Missing the 'token' and/or
'username' parameter(s) in header and/or body, respectively"));
} else {
// Delete the user's account. So sad to see them go... :'(
User.findOne({"token": header.token, "username": body.username}, "+token +_id",
function(err, user) {
if (err) {
return callback(err);
} else {
user.remove(function(err) {
if (err) {
return callback(err);
} else {
// Everything went according to plan. Return a SuccessEnvelope to the user.
callback(new SuccessEnvelope());
}
});
}
});
}
break;
Can anyone see what I did wrong? Any help would be fantastic. Thanks in advance!
EDIT: It's probably also a good idea to include my test cases...
deleteUser = {
"header": {
"type": "user",
"method": "delete",
"token": ""
},
"body": {
"username": ""
}
}
describe("Delete user", function() {
it("should return a MissingEnvelopeDataError when deleting a user without a token or
username", function(done) {
connection.write(JSON.stringify(deleteUser));
connection.on("data", function(res) {
res = JSON.parse(res.toString());
res.header.should.have.property("type", "error");
res.header.should.have.property("errorType", "MissingEnvelopeDataError");
done();
});
});
it("should return a SuccessEnvelope when deleting a user", function(done) {
deleteUser.header.token = user.token;
deleteUser.body.username = user.username;
connection.write(JSON.stringify(deleteUser));
connection.on("data", function(res) {
res = JSON.parse(res.toString());
console.dir(res);
res.header.should.have.property("type", "success");
// res.body.should.be.empty
(function() {
if (Object.keys(res.body).length == 0) {
return true;
} else {
return false;
}
})();
done();
});
});
});
The user variable you see here is just a simple object, which stores all of the user info.
As usual, I'm an idiot and don't follow my own API.
The callback function that's being passed takes two parameters: err and response. I was forgetting to pass null as my error, so the code was doing exactly what it should have been doing. DOH! Thanks for the responses, everyone!
I am currently programming a socket server in node.js using the json-socket module, and am having some trouble.
Currently when a client connects to the server they send a command in a json object with some data for instance a login would look like this
{ type : 'login', data : { username: 'Spero78' } }
to deal with these requests i have a commands object
var commands = {
'login' : authUser,
'register' : userRegister
}
and these functions are called by server.on
server.on('connection', function(socket) {
console.log('Client Connected');
socket = new JsonSocket(socket);
socket.on('message', function(message) {
if(message.type != undefined) {
if(commands[message.type]){
var response = commands[message.type].call(this, message.data);
if(response != undefined){
console.log(response);
socket.sendMessage(response);
} else {
console.log("No Response!");
}
} else {
console.log('Unexpected Command!');
}
}
});
});
The functions return javascript objects but the response var is always undefined and the "No Response!" message is always printed
Here is the authUser function
function authUser(data){
console.log('Auth: ' + data.username);
database.query('SELECT * FROM players WHERE username = ?', [data.username], function(err, results) {
if(results.length < 1){
console.log('Bad Login!');
var response = {
type : 'badlogin',
data : {
//...
}
}
return response;
}
var player = results[0];
var response = {
type : 'player',
data : {
//...
}
}
return response;
});
}
Is there a better way of doing this? or am i missing something that is causing the objects to not return
database.query() is asynchronous, so when you call this function, nodejs don't wait the response of the callback to go to next instruction.
So the value tested on your condition is not the return in the callback, but of the whole authUser function, that's why it's always undefined.
You probably need tor refactor your code.