eelzee/intacct_integration

Library for integration with Intacct (https://us.intacct.com/). Built for Drupal usage

This package's canonical repository appears to be gone and the package has been frozen as a result.

1.2.0 2017-03-16 01:34 UTC

This package is auto-updated.

Last update: 2019-01-31 03:53:21 UTC


README

Overview

This package provides a PHP interface to the IntAcct xml web api. It provides a series of namespaced classes which, when invoked, will allow the module implementer to easily make a call out to their remote intacct database to perform an operation on an object there.

The module is built to be asynchronous, but currently operates synchronously until the latter can be more fully tested. This module is in pre-alpha release stage.

As stated, this is a partial implementation. We hope in the act of open-sourcing this work, we can both get more thorough coverage of intacct methods, as well as providing benefit to others in the open source community. It probably goes without saying, but to use this module, you must already have a paid Intacct account.

Requirements

This module requires a local install of composer and git. It also requires php 5.6 or greater, due to certain package dependencies.

Installation

  1. Obtain necessary account and credentials from Intacct. This module is useless without an account with them.
  2. Execute composer require eelzee/intacct_integration within your project
  3. Once composer installation is complete:
    1. If running standalone: copy the file intacct_configuration.example.yml from the installed composer package to intacct_configuration.yml in the same location, and configure the settings there to be appropriate to your installation.
    2. If using in Drupal: copy the file intacct_configuration.example.yml from the installed composer package root to private:///intacct_configuration.yml (where 'private://' is your drupal private files directory) and configure the settings there to be appropriate to your installation.

Usage

Before we get into any examples, it's worth talking about the general patterns seen in the api.

General patterns in the Intacct integration api

All handler methods are static

Every creation method is static, so to make a call, you must simply find the appropriate static method, and invoke it with either one or two sets of data. The first data array will always be the structured data you intent to populate the request with. The second is not used quite as often, but it affects how the data is processed.

All handler methods return a response object

Every creation method returns a response object, with methods that detail the response data, the response success, and a method called 'then' which allows chaining of the response to another invocation.

All handler methods are chainable

The then method accepts one argument, an object that implements the response interface. We test for response success using the isSuccessful method (which evaluates communication success, primarily), and then we can take other action with the response depending on what we need to do. In this case, we just want to assert that the response was successful. If it was not, the fail method (part of the phpunit suite) would generate an error message that included both the generated request and response xml that comprised the request.

Api Documentation

This module relies on phpDocumentor to provide api documentation. This is not included in the repo just yet - if you need this:

  1. Make sure you have phpdoc installed on your system.
  2. Navigate to the composer package root (vendor/eelzee/intacct_integration)
  3. Run the tool on the 'src' folder, specifying an output directory for the docs, e.g.: phpdoc -d src -t api_documentation
  4. Open the docs in a browser. The doc index page for the example given would be at (from the composer root) vendor/eelzee/intacct_integration/api_documentation/index.html

Examples

Example 1: Creating a class

There are PHPUnit tests in the vendor/eelzee/intacct_integration/tests folder that also serve well as examples. To start, let's look at a simple one of these, taken from tests/IntacctObject/IntacctClassTest.php:

  /**
   * Standardizes the data used for the tests.
   */
  public static function getMockData() {
    $data = [
      // NOTE: should ultimately correspond to Drupal node id.
      'CLASSID' => 'TEST' . uniqid(),
      // NOTE: should ultimately correspond to Vehicle VIN.
      'NAME' => 'TEST' . uniqid(),
      // (Vehicle Year Make Model)
      'DESCRIPTION' => date('Y') . ' Dummy Class',
    ];
    return $data;
  }

  /**
   * Tests the createClass operation.
   *
   * @group active
   *
   * @return array
   *   An array consisting of two elements:
   *   0: The array defining the data used to construct the class object.
   *   1: The response object from the create operation, or NULL if the
   *   response failed.
   */
  public function testCreate() {
    static $test_name = "Testing create class";
    $vehicle_info = self::getMockData();
    $response = IntacctClass::create($vehicle_info)
      ->then(function (IntacctResponseInterface $response) {
        if (!$response->isSuccessful()) {
          $this->fail(sprintf("Cannot continue.  Errors: %s\n\nrequest xml: %s\n\nresponse xml: %s", print_r($response->getErrors(), TRUE), $response->getRequestXml(), $response->getResponseXml()));
          return NULL;
        }
        return $response;
      });
    Utilities::handleResponse($this, $response, $test_name);

    return $response;
  }

The first method, getMockData, simply returns an array of data, where the keys correspond to fields you would pass to the Create_class method for the class object in the Intacct API. This is done in one spot so that we get consistent testing creation data across and between tests.

The second method is the phpunit test that calls out to the intacct api to create a new class object. You can see that we have passed it our mocked data, and called a then method with the returned result:

    $response = IntacctClass::create($vehicle_info)
      ->then(function (IntacctResponseInterface $response) {
        if (!$response->isSuccessful()) {
          $this->fail(sprintf("Cannot continue.  Errors: %s\n\nrequest xml: %s\n\nresponse xml: %s", print_r($response->getErrors(), TRUE), $response->getRequestXml(), $response->getResponseXml()));
          return NULL;
        }

In the callback handler, we simply make an assertion that the request was successful. What success means is standardized:

  • The request has resolved. This library is intended to allow async operation (eventually), so if you call this method before the communication has resolved or timed out, you will trigger an exception. If you need to halt operations until it resolves, just use the 'wait' method in the callback:
      $response = IntacctClass::create($vehicle_info)
        ->then(function (IntacctResponseInterface $response) {
          if (!$response->isSuccessful()) {
            $response->wait();
            $this->fail(sprintf("Cannot continue.  Errors: %s\n\nrequest xml: %s\n\nresponse xml: %s", print_r($response->getErrors(), TRUE), $response->getRequestXml(), $response->getResponseXml()));
            return NULL;
          }
    
-  The authorization for the intacct 'control' and 'authentication' blocks are successful (see [here](https://developer.intacct.com/wiki/constructing-web-services-request#Logon,%20Verification%20and%20Requests%20using%20the%20Intacct%20XML%20DTD)). 
- The *operation* was successful.  This means it was successfully executed remotely without error - you could be running a query for items, and it is possible and even likely for it to pass this test, and return an empty result set at the same time.

...more documentation coming soon...