4

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

Taylorsuk
  • 1,419
  • 1
  • 16
  • 51
  • 1
    I think you're getting little traction on this question because it amounts to "how do I write a cloud function to update a user"? This is okay, but it needs: (a) clarity on input, like where is the user-identifying feature in that giant pile of JSON, (b) delete the giant pile of JSON, and (c) at least an attempt at the code -- the bar is pretty low here, but talking to SO people is like talking to Parisians. If you try English, only louder, you'll get snubbed, but a humble, even bungled attempt at French will usually get you generous help. – danh May 01 '15 at 02:31
  • Great. Answered below based on the flow described at parse.com for using Stripe. It assumes the logged in user is the user who is making the payment. – danh May 01 '15 at 14:25

2 Answers2

3

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;
    });
}
danh
  • 62,181
  • 10
  • 95
  • 136
Taylorsuk
  • 1,419
  • 1
  • 16
  • 51
  • I use email as the username. Many thanks for your time, coaching and code danh. I'm sure you can see where I am weak in my JS, do you have any advice on where I can improve without having to go through everything from scratch like most tutorials. – Taylorsuk May 01 '15 at 18:52
  • glad to help. seems like you're off to a good start. i think the way to go is to just keep writing (and editing, and re-editing), striving for simplicity and clarity. – danh May 01 '15 at 19:12
  • I think that `var email = stripeResponse.email;` needs to be `var email = stripeResponse["email"];` ? – Taylorsuk May 01 '15 at 19:16
  • those forms are almost synonymous. in most cases, i go for the dot notation. see here http://stackoverflow.com/questions/4968406/javascript-property-access-dot-notation-vs-brackets – danh May 01 '15 at 19:36
2

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();
}
danh
  • 62,181
  • 10
  • 95
  • 136
  • Firstly this is fantastic - thank you. However, I may have miss lead you slightly. I am not trigging this code from within my app - this is an incoming webhook from stripe following successful charge of a card on an external site. I need to just get customer email from Stripe (requiring a call back to Stripe) > query parse Users for that email / username and then update their record. – Taylorsuk May 01 '15 at 15:04