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.

Monday, January 30, 2012

How to setup FreeRDP from Linux (Ubuntu) to Windows 7

This one's for all those tech geeks out there...

There's finally a working solution to use RemoteApp from Windows - that means you can finally have a RELIABLE seamless desktop with a remote Windows PC on you linux machine.

First off: why do this?

I was using VirtualBox with their great seamless mode for a while with Ubuntu, but it was never really stable. After a few hours it would crash every time. When it was running, it ran well. But it never worked for very long.

The xFreeRDP solution lets you connect to a remote computer and use windows programs seamlessly with Microsoft's RemoteApp (which is built in to Win7, Vista, Server)


How...

1. Make sure you have Windows 7 ENTERPRISE or ULTIMATE or Windows Server.  This won't work on Windows 7 Pro.

2. Download the latest version of FreeRDP from here: https://github.com/FreeRDP/FreeRDP

3. Setup your system for compiling it - on Ubuntu you need to do the following:

$ sudo apt-get install build-essential git-core cmake libssl-dev libx11-dev libxext-dev libxinerama-dev libxcursor-dev libxdamage-dev libxv-dev libxkbfile-dev libasound2-dev libcups2-dev

$ sudo apt-get install libavutil-dev libavcodec-dev 

$ cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_SSE2=ON .

$ make

$ sudo make install

$ sudo cat > /etc/ld.so.conf.d/freerdp.conf 
/usr/local/lib/freerdp
/usr/local/lib

$ ldconfig


4. On your Windows 7 machine, run Regedit and under HKLocalMachine\SOFTWARE\Policies\Microsoft\Windows NT add a key named "Terminal Services"

5. Under that, add a DWORD32 value named "fAllowUnlistedRemotePrograms" and set the value to 1

If you don't do this, you will get the following error: RAIL exec error: execResult=RAIL_EXEC_E_NOT_IN_ALLOWLIST NtError=0x15


6. run the following command on your Linux box


$ xfreerdp -u <username>  --app --plugin ./usr/local/lib/freerdp/rail.so --data "%windir%\system32\cmd.exe" -- <ip of your windows machine>

Note your rail.so path may be different, so you may have to search for it.

That's it... you can now launch programs from the cmd shell.

Monday, January 16, 2012

Could SoLoMo Be the Key to Powering Your Mobile Strategy?

The most recent buzz on mobile is that branded mobile apps could be the most powerful form of advertising yet, specifically because they relay a company’s message in a much more active way than just print ads or websites. In fact, downloading a mobile app that is informational or provides a specific utility has been shown to engage consumers even more than entertainment or gaming. How? The answer could be SoLoMo.

Broadly speaking, SoLoMo refers to the new generation of technologies that integrate social media (network content and shareability), local (location-based technologies such as GPS and real-time activity) and mobile (smartphones capabilities that render technology useable anytime, anywhere).
  
So what are we talking here?  Sending your customers push notifications on special deals or coupons when they happen to be in your neighborhood?  It may not be as complicated as that. 

If you’re thinking of creating a branded mobile app for your company, consider SoLoMo as a way to devise your mobile strategy. 

For instance, if you’re a retailer, you may already be using social media channels such as Facebook, Twitter and Youtube.  You probably also have your own blog. So consider integrating these as a tab into your app, to offer your customers valuable content in the form of tips and hints to help them find the product they’re looking for and attain a more satisfying shopping experience when they’re in your store. 

If you’re a food truck, take a hint from the “Lo” or SoLoMo and integrate a geo-location tab in your mobile app that helps your customers find you whether you’re at your usual haunt or may be venturing out to a new neighborhood.   Your customers will love being able to have instant access to your location when they’re in the mood for some food. 

And finally, the “Mo” of SoLoMo could just be the key to attaining discoverability for your mobile app.  Text message is one of the integral features of phones that capitalizes on being able to connect with consumers anytime, anywhere.  Consider using one of the popular DIY mobile app creation tools out there to create a mobile app that can be sent out to customers via text message links. 

No, SoLoMo isn’t a tropical locale that you can score a trip to via TravelZoo. But it could just be your road to devising a mobile app that generates that extra level of interactivity with your customers and lands you your next sale!