Quickbooks oAuth2 Meteor examples

Good evening,

I am just starting to look into adding QuickBooks support for my application and was poking around at the QuickBooks documentation and it points out to a package for npm https://github.com/mcohen01/node-quickbooks.

I have been looking through the sample app but I| have never played with express before and that is what it is written in.

My project is currently up to date with meteor version 1.6.1.1 and is using Blaze templating and iron:router.

I am hoping someone out there has some experience setting up the oauth2 flow for QuickBooks online and meteor and can maybe give me a push in the right direction.

I have been google searching for any sort of Meteor code samples of doing the oauth2 and quickbooks but have come up blank.

I would apprecaite any help someone is able to provide.

Have you checked these atmosphere packages?

We call QB from Meteor. I’ll see what I can share.

1 Like

@robfallows The only issue with those packages are that half are for login credentials only and the other half seem to only use oauth1. Quickbooks has a requirement of using oauth2 for all new developer accounts. That is the part I am clueless on in converting the ember examples to something I can work with in Meteor.

@maxhodges anything you can share in the oath2 workflow would be greatly apprecaited. Once connected the rest of the package seems pretty easy to use.

1 Like

If you’re happy to roll your own, you could try following my “cookbook” approach.

@robfallows I will def have a look at this tonight thank you.

1 Like

@robfallows I had a look at your boilerplate code last night but was unsuccessful in rolling my own. Not sure what I will do next. This oAuth2 stuff is completely out of my wheelhouse.

I honestly thought there would be some sort of package out there based on how many people use quickbooks but I guess not lol.

Well guess I am back to google to try to figure this out.

How far did you get? I’ve had a quick look at the intuit OAuth2 docs and they seem at first sight to be reasonably well presented.

If you have a repo I could take a look?

sending a bit more by PM

const debug = false;

import _ from "lodash";
import Promise from "bluebird";
// NOTE: We cannot simply `Promise.promisifyAll()` QuickBooks because it does
// not call it's callback with an `Error`, just a plain object.
import QuickBooks from "node-quickbooks";

import { Meteor } from "meteor/meteor";

import * as u from "../utils";

// Initialise the collection that stores the QuickBooks oauth settings.
// NOTE This collection is shared between all the apps
const QuickbooksOAuthSettings = new Mongo.Collection("quickbooksOAuthSettings");

// Get the QuickBooks settings from `Meteor.settings.public`
// @TODO Move the QuickBooks settings out of public
const settings = _.get(Meteor, "settings.quickbooks", {});
const keys = _.get(settings, "keys", {});

// Helper to get the `qbo` instance. We always pass `qbo` to functions so that
// we stub it for testing (which we're not currently doing...)
const getQbo = function(qbo) {
  // If we are passed a value for `qbo` return it immediately
  if (qbo) return Promise.resolve(qbo);

  return Promise.try(() => {
    // If we have 'oauth_prod_sandbox' credentials in settings, use those
    if (!_.isEmpty(_.get(settings, "oauth_prod_sandbox"))) {
      return _.get(settings, "oauth_prod_sandbox");
    }

    // Otherwise, get the QuickBooks oauth settings from the collection
    return u.wrapSyncMethod(QuickbooksOAuthSettings, "findOne", {
      name: "quickbooksAuthentication"
    });
  }).then(oauthSettings => {
    u.checkNotEmpty(settings, "QuickBooks settings cannot be empty #OF2GXb");
    u.checkNotEmpty(keys, "QuickBooks keys cannot be empty #YxQkM3");
    u.checkNotEmpty(
      oauthSettings,
      "QuickBooks oAuth settings cannot be empty #kR8En5"
    );

    if (debug)
      console.log("qbo settings #lpU33C", keys, oauthSettings, settings);

    // Return the instantiated `Quickbooks` class
    return new QuickBooks(
      keys.consumerKey,
      keys.consumerSecret,
      oauthSettings.oauth_token,
      oauthSettings.oauth_token_secret,
      oauthSettings.realmId,
      settings.isSandbox,
      Meteor.isDevelopment // Enable debug in development only
    );
  });
};

/**
 * Execute a call against the QuickBooks API
 * @param {Object} qbo - The node-quickbooks instance
 * @param {String} methodName - The name of the method to call (eg createCustomer)
 * @param {...} args - The argument(s) to path to the method
 * @returns {Promise} - It will resolve or reject with a Meteor.Error
 */
export const execute = function(qbo, methodName, ...args) {
  return getQbo(qbo).then(qbo => {
    return new Promise((resolve, reject) => {
      if (!_.isFunction(qbo[methodName])) {
        return reject(
          new Meteor.Error(
            "quickbooks-invalid-method",
            `This method (${methodName}) does not exist #inrNtn`
          )
        );
      }

      qbo[methodName](...args, (error, response) => {
        if (error) {
          log("error", "QuickBooks API returned an error #YqRdT1", {
            error,
            methodName,
            args
          });
          return reject(
            new Meteor.Error(
              "quickbooks-error",
              "QuickBooks API returned an error #YqRdT1",
              JSON.stringify(error)
            )
          );
        } else {
          log("debug", "QuickBooks API returned success #jybJWm", {
            response,
            methodName,
            args
          });
          return resolve(response);
        }
      });
    });
  });
};

export default execute;

if (Meteor.isDevelopment) {
  Meteor.methods({
    qboApi: execute
  });
}

Thank you very much. I will have a look at this tonight.