Graphcool / graphcool-framework

Apache License 2.0
1.77k stars 131 forks source link

Braintree module #40

Open marktani opened 6 years ago

marktani commented 6 years ago

Issue by marktani Tuesday Mar 07, 2017 at 16:00 GMT Originally opened as https://github.com/graphcool/prisma/issues/130


A Braintree module should be added to https://github.com/graphcool/modules

marktani commented 6 years ago

Comment by stevewpatterson Wednesday Jun 21, 2017 at 21:37 GMT


This is a relatively high level overview of the flow for integrating braintree into your project. Hopefully this can help someone else if they decide to go with braintree.

The obvious benefit with braintree is that paypal payment methods are handled in pretty much the same way as CC payment methods, and so you give your customers the option to use either without having to change your backend implementation.

NOTE: all the code examples use AWS Lambda (NodeJS 4.3 runtime), going through AWS API Gateway as a proxy, and the code is barebones/not complete.

1. First thing I do is create braintree customers once they are created This is optional but I find it to be the easiest thing. You can alternatively create customers when they create their first billing method. I set up a subscription function in the graphcool UI, which basically hits a lambda function when Users are created.

var braintree = require('braintree')
var gateway = braintree.connect({
    environment: braintree.Environment.Sandbox,
    merchantId: '__MERCHANT_ID__',
        publicKey: '__PUBLIC_KEY__',
        privateKey: '__PRIVATE_KEY__'
});
exports.handler = function(event, context, callback) {
    var obj = JSON.parse(event.body)

    gateway.customer.create({
        firstName: obj.data.User.node.firstname,
        lastName: obj.data.User.node.lastname,
        email: obj.data.User.node.email
    }, function (err, result) {

        if (result.success) {
                console.log(result.customer.id)
                //call graphcool backend to update user with result.customer.id for later reference
        }
    }
}

2. Your client needs a token which braintree provides in order to instantiate your form I call a lambda function that basically just runs this:

var braintree = require("braintree");
var gateway = braintree.connect({
    environment: braintree.Environment.Sandbox,
    merchantId: '__MERCHANT_ID__',
        publicKey: '__PUBLIC_KEY__',
        privateKey: '__PRIVATE_KEY__'
});
exports.handler = function(event, context, callback) {
        gateway.clientToken.generate({}, function (err, response) { 
             console.log(response.clientToken)
             //return token
        }
}

Once you have a token you can use it to instantiate the client in your front end javascript. You can find the code for this in their guides.

3. On form submission, get a payment method 'nonce'. This nonce is used to actually create the billing method (in braintree) later. So I have a lambda function which I hit with that nonce and the users braintree id.

var braintree = require("braintree");
var gateway = braintree.connect({
    environment: braintree.Environment.Sandbox,
    merchantId: '__MERCHANT_ID__',
    publicKey: '__PUBLIC_KEY__',
    privateKey: '__PRIVATE_KEY__'
});

exports.handler = function(event, context, callback) {
    var obj = JSON.parse(event.body)

    gateway.paymentMethod.create({
        customerId: obj.braintreeId,
        paymentMethodNonce: obj.nonce,
        options: {
            makeDefault: true,
            failOnDuplicatePaymentMethod: false
        }
    }, function (err, result) {
        if (result.success) {
            var paymentMethod = result.paymentMethod

            if (paymentMethod instanceof braintree.CreditCard || paymentMethod instanceof braintree.PayPalAccount) {

                console.log(paymentMethod)
                //return paymentMethod
            }
        } else {
            console.log(result, err)
        }
    });
}

NOTE: whether its paypal or CC both return the same parent object with a token identifier

4. Actually Create BillingMethod in Graphcool Backend I use Apollo, but basically whatever method, just fire off a mutation to create a new node, and pass the token in the result from the last request to your mutation. This will save that token, which is what is used later to make actual transactions on that billing method.

5. Making Transactions I'll leave this to you to decide how you want to go about firing off the code to make a transaction, but it looks something like this when you actually do it. For me I have Purchase objects and when one is created it fires off a function. You just need the associated billing methods token which we got in step 3, which should be saved in your Graphcool backend.

var braintree = require("braintree")
var gateway = braintree.connect({
    environment: braintree.Environment.Sandbox,
    merchantId: '__MERCHANT_ID__',
    publicKey: '__PUBLIC_KEY__',
    privateKey: '__PRIVATE_KEY__'
});

exports.handler = function(event, context, callback) {
    var obj = JSON.parse(event.body)

    gateway.transaction.sale({
        amount: obj.data.Purchase.node.price+".00",
        paymentMethodToken: obj.data.Purchase.node.billingMethod.token,
        options: {
            submitForSettlement: true
        }
    }, function (err, result) {
        if (result.success) {
            console.log('success')
        } else {
            console.log('error')
        }
    });
};