Saturday, February 4, 2012

How to use Keith Palmer's PHP-DevKit to integrate a web app with Quickbooks Online

So here at Appguppy, we've been trying to enhance our e-commerce features to make it easier for our customers to sell stuff on their apps.  One of the initiatives is to integrate our system with Quickbooks so that people can easily pull in their products and sell the through their app.

For this we needed to use Intuit's Partner Platform and their SDK.  Unfortunately, they don't have a set of libraries for PHP, but since the IPP now allows oauth and XML, it is not too hard to integrate.  Still, there are dozens of object types and thousands of properties that we need to build in, and that's very time consuming.

So along comes a new version of Keith Palmer's excellent PHP-DevKit. Which finally supports oauth. The problem is, it's not immediately obvious how to use it.  Below is a step by step guide:

1. Download the latest devkit build. Unfortunately, its currently only available via SVN, so you'll have to install an SVN client and point it to this url:

svn checkout https://code.intuit.com/svn/repos/php_devkit
 
2.To create our simple app, we put it on a test server in our /var/www directory.  You should now have a file Quickbooks.php and a sub-directory Quickbooks under /var/www

3. Make sure you have mcrypt installed in PHP, you can check this with phpinfo().  If not, download and install it.

4. Make a new file index.php and put the following in the file:

require_once 'QuickBooks.php';


$token = 'sfewtw4et3w45sfsfsdfdsf';
$oauth_consumer_key = 'sfewtwsetsgsdsdfsdc';
$oauth_consumer_secret = 'dsffwe5tr4w5sdfsdfsdfsdfsdf';

// This is the URL of your OAuth auth handler page
$this_url = 'http://myserver/index.php';

// This is the URL to forward the user to after they have connected to IPP/IDS via OAuth
$that_url = 'http://myserver/other.php';

$dsn = 'mysql://test:test@localhost/quickbooks';

// You should set this to an encryption key specific to your app
$encryption_key = 'abcd1234';

// The user that's logged in
$the_username = 'your_app_username_here_2';

// The tenant that user is accessing within your own app
$the_tenant = 12345; 
if (!QuickBooks_Utilities::initialized($dsn))
  {
    // Initialize creates the neccessary database schema for queueing up requests and logging
    QuickBooks_Utilities::initialize($dsn);
  }

$IntuitAnywhere = new QuickBooks_IPP_IntuitAnywhere($dsn, $encryption_key, $oauth_consumer_key, $oauth_consumer_secret, $this_url, $that_url);

if ($IntuitAnywhere->handle($the_username, $the_tenant))
  {
    ; // The user has been connected, and will be redirected to $that_url automatically. 
  }
else
  {
    die('Oh no, something bad happened: ' . $IntuitAnywhere->errorNumber() . ': ' . $IntuitAnywhere->errorMessage());
  } 
  
Let's also make a file called other.php

require_once 'QuickBooks.php';


$token = 'sfewtw4et3w45sfsfsdfdsf';
$oauth_consumer_key = 'sfewtwsetsgsdsdfsdc';
$oauth_consumer_secret = 'dsffwe5tr4w5sdfsdfsdfsdfsdf';

// This is the URL of your OAuth auth handler page
$this_url = 'http://myserver/index.php';

// This is the URL to forward the user to after they have connected to IPP/IDS via OAuth
$that_url = 'http://myserver/other.php';

$dsn = 'mysql://test:test@localhost/quickbooks';

// You should set this to an encryption key specific to your app
$encryption_key = 'abcd1234';

// The user that's logged in
$the_username = 'your_app_username_here_2';

// The tenant that user is accessing within your own app
$the_tenant = 12345; 
if (!QuickBooks_Utilities::initialized($dsn))
  {
    // Initialize creates the neccessary database schema for queueing up requests and logging
    QuickBooks_Utilities::initialize($dsn);
  } 
 
// Set up the IPP instance                                                                                                                                                                                                    
$IPP = new QuickBooks_IPP($dsn);

// Set up our IntuitAnywhere instance                                                                                                                                                                                         
$IntuitAnywhere = new QuickBooks_IPP_IntuitAnywhere($dsn, $encryption_key, $oauth_consumer_key, $oauth_consumer_secret);

// Get our OAuth credentials from the database                                                                                                                                                                                
$creds = $IntuitAnywhere->load($the_username, $the_tenant);

// Tell the framework to load some data from the OAuth store                                                                                                                                                                  
$IPP->authMode(
               QuickBooks_IPP::AUTHMODE_OAUTH,
               $the_username,
               $creds);

// Print the credentials we're using                                                                                                                                                                                          
print_r($creds);

// This is our current realm                                                                                                                                                                                                  
$realm = $creds['qb_realm'];

// Load the OAuth information from the database                                                                                                                                                                               
if ($Context = $IPP->context())
  {
    // Set the DBID                                                                                                                                                                                                           
    $IPP->dbid($Context, 'something');

    // Set the IPP flavor                                                                                                                                                                                                     
    $IPP->flavor($creds['qb_flavor']);

    // Get the base URL if it's QBO                                                                                                                                                                                           
    if ($creds['qb_flavor'] == QuickBooks_IPP_IDS::FLAVOR_ONLINE)
      {
        $IPP->baseURL($IPP->getBaseURL($Context, $realm));
      }

    print('Base URL is [' . $IPP->baseURL() . ']' . "\n\n");
     $CustomerService = new QuickBooks_IPP_Service_Customer();

    $perpage = 3;
    for ($page = 1; $page <= 3; $page++)
      {
        print('PAGE ' . $page . "\n\n");

        $list = $CustomerService->findAll($Context, $realm, null, null, $page, $perpage);

        foreach ($list as $Customer)
          {
            print('Name [' . $Customer->getName() . ']' . "\n\n");
          }

        print("\n\n\n");
      }

    print("\n\n\n\n");
    print('Request [' . $IPP->lastRequest() . ']');
    print("\n\n\n\n");
    print('Response [' . $IPP->lastResponse() . ']');
    print("\n\n\n\n");
  }
else
  {
    die('Unable to load a context...?');
  }
 

5. Now, a little aside on how oauth works with PHP-DevKit -
  • The first request is made by the original php page (in our case index.php - but you can specify whatever you want in $this_url) to the oauth server with your oauth consumer secret and and oauth consumer key (I'll tell you how to get those in a sec).  This is done by the handle() function in the IntuitAnywhere object.
  • The handle() function then redirects the user to the authentication URL, which shows one of those login/connect screens to the user (like you see when you use a Twitter app).  
  • Once the user accepts the app, Intuit sends the user back to the page they were on (it will return to whatever is in $this_url -- in our case index.php).  This time the handle() function sees that there is a token in the HTTP request and saves the token.  It then redirects the user to another page ($that_url, or in our case other.php).
  • In other.php, we re-initialize the IntuitAnywhere object, but instead of using handle() to get the token, we use load() to load the token that was saved in the previous step.
  • We then create an IPP object specifying that we're using oauth, and that will provide us with a context from which to make calls.
6. Now let's make this thing work.  First, get your token, oauth consumer key and oauth consumer secret from Intuit's Developer Center under Manage Apps -> (click on your Dev Master app) -> "App Tokens and Keys".  In both index.php and other.php set the lines marked in purple above to those values.

7. Replace myserver (marked in green) in both files to your server URL.   Also update the Mysql username and password (marked in blue) to yours

8. Create a database in mysql called quickbooks. This will be used to save tokens.  All the tables will be created automatically by PHP Devkit.

9. That's it - now point your browser to http://myserver/index.php - it should redirect to the Intuit Anywhere authorization screen. Users can enter their username and password there and click to authorize your app. Once they do, it will go to other.php and you should see a list of customers for that user.

Hopefully this makes oauth with devkit a bit easier to get started.