Integrating with Kashflow using PHP

Kashflow is a leading provider of cloud-based accounting software - it completely replaces Sage or Quickbooks and is much easier and faster to use. In this blog post I'm going to explain how you can get your website to talk to Kashflow using PHP.

If you're a web developer, this is cool simply because it's cool. If you're a business owner or a financial type, this is cool because you can automate some of your boring finance stuff and spend more time on important things like Social Media and late lunches.

Our solution uses PHP's SoapClient class. Head on over to Kashflow's developer resources page for alternatives.

Configure your Kashflow account

Before you do any coding, you need to activate the Kashflow API on your account. I recommend that you create yourself a Kashflow account specifically for testing the API - luckily there's a free trial so it won't cost you anything.

  1. Login to your account
  2. Go to the "Settings" area
  3. Choose "API Settings"
  4. Tick the "Enable the API for my KashFlow account" box
  5. Optionally (but recommended), restrict access to particular IP addresses
  6. Press "update"

How the API works

The Kashflow API is based on SOAP, which is a widely used standard for software to communicate. Kashflow will act as a SOAP server, and your code will be a SOAP client.

When you need to talk to Kashflow, your code will send a SOAP request and then receive a SOAP response. PHP 5 has a built-in class called SoapClient which makes this very easy:

$client = new SoapClient("https://securedwebapp.com/api/service.asmx?WSDL");

This one line of code looks up all the functionality that the Kashflow API offers, and makes a ready-to-use object which has all the same functions as the API. All of the complicated communication stuff happens automatically behind the scenes.

Each function created by SoapClient takes a single parameter which should be an array containing the information that the API requires. For example:

$parameters['UserName'] = "username";
$parameters['Password'] = "password";
$response = $client->GetAccountOverview($parameters);

Making it generic

Since all of the Kashflow API calls require your username and password, it makes sense to do some refactoring. What I'd really like is to do this:

$kashflow = new Kashflow("username","password");
$kashflow->getAccountOverview();

This is cool because I don't even have to think about any of the SOAP stuff - I can concentrate on what needs to happen rather than how. So I've created a class, as follows:

class Kashflow
{
	private $m_client   = NULL;
	private $m_username = "";
	private $m_password = "";

	public function __construct($username,$password)
	{
		$this->m_client   = new SoapClient("https://securedwebapp.com/api/service.asmx?WSDL");
		$this->m_username = $username;
		$this->m_password = $password;
	}

	public function getAccountOverview()
	{
		return $this->makeRequest("GetAccountOverview");
	}

	private function makeRequest($fn)
	{
		$parameters['UserName'] = $this->m_username;
		$parameters['Password'] = $this->m_password;
		return $this->m_client->$fn($parameters);
	}
}

The constructor handles the setup of the SoapClient object and stores the username and password for subsequent requests. This saves having to specify it every time I want to make a call.

The magic happens in makeRequest. I pass the name of the API function to makeRequest, which then builds the parameters and calls into Kashflow.

I need more parameters

So what happens if you need to pass more parameters to the Kashflow API? You need an enhanced version of makeRequest:

private function makeRequest($fn,$extra = NULL)
{
	$parameters['UserName'] = $this->m_username;
	$parameters['Password'] = $this->m_password;
	if(NULL != $extra)
		$parameters = array_merge($parameters,$extra);
	return $this->m_client->$fn($parameters);
}

This allows you to optionally pass additional parameters through to Kashflow, for example:

public function getSupplier($code)
{
	$parameters['SupplierCode'] = $code;
	return $this->makeRequest("GetSupplier",$parameters);
}

In the above example, the supplier code gets merged with the username and password before being passed on to Kashflow.

Handling errors

Errors happen all the time - you need to handle them! Let's update our class to throw an exception when the API call fails.

private static function handleResponse($response)
{
	if("NO" == $response->Status)
		throw(new Exception($response->StatusDetail));
	return $response;
}

private function makeRequest($fn,$extra = NULL)
{
	$parameters['UserName'] = $this->m_username;
	$parameters['Password'] = $this->m_password;
	if(NULL != $extra)
		$parameters = array_merge($parameters,$extra);
	return self::handleResponse($this->m_client->$fn($parameters));
}

makeRequest has been updated to delegate the error checking to handleResponse, which checks if Kashflow returned "NO", and either throws an exception or just returns the response.

Creating a sales invoice

Wouldn't it be cool if you could automatically create a sales invoice every time you sold something?

$kashflow = new Kashflow("username","password");
$i = new KashflowInvoice("customer id","invoice number","invoice date","due date");
$i->addLine("qty","net","vat","vat rate","nominal id","description","project id");
$kashflow->insertInvoice($i);

Don't worry about the KashflowInvoice class for now - the interesting bit is how the insertInvoice function prepares the data. At first glance, you would think that all you need to do is pass through $lines as part of the invoice data:

$lines[] = array
(
	"LineID"      => 0,
	"Quantity"    => "qty",
	"Description" => "description",
	"Rate"        => "unit net",
	"ChargeType"  => "nominal id",
	"VatAmount"   => "line vat",
	"VatRate"     => "vat rate",
	"Sort"        => 1,
	"ProductID"   => 0,
	"ProjID"      => "project id"
);

$parameters['Inv'] = array
(
	"InvoiceNumber" => "invoice number",
	"InvoiceDate"   => "invoice date",
	"DueDate"       => "due date",
	"CustomerID"    => "customer id",
	"Lines"         => $lines,
	"NetAmount"     => "net",
	"VATAmount"     => "tax"
);

$response = $this->makeRequest("InsertInvoice",$parameters);

But it's not that simple. The Kashflow API specification requires that the lines parameter is an array of InvoiceLine objects. SoapClient enforces this and will fail unless you obey!

The solution is to use PHP's SoapVar object to wrap the invoice lines, as follows:

$line = array
(
	"LineID"      => 0,
	"Quantity"    => "qty",
	"Description" => "description",
	"Rate"        => "unit net",
	"ChargeType"  => "nominal id",
	"VatAmount"   => "line vat",
	"VatRate"     => "vat rate",
	"Sort"        => 1,
	"ProductID"   => 0,
	"ProjID"      => "project id"
);

$lines[] = new SoapVar($line,0,"InvoiceLine","KashFlow");

$parameters['Inv'] = array
(
	"InvoiceNumber" => "invoice number",
	"InvoiceDate"   => "invoice date",
	"DueDate"       => "due date",
	"CustomerID"    => "customer id",
	"Lines"         => $lines,
	"NetAmount"     => "net",
	"VATAmount"     => "tax"
);

$response = $this->makeRequest("InsertInvoice",$parameters);

SoapClient knows that SoapVar means "an object". The SoapVar constructor's first parameter is the data, the second is encoding, the third is the name of the object, and the fourth is the namespace. The PHP documentation for SoapVar is a bit sketchy so I just pass 0 for encoding and it seems to work. If you know better, please comment!

Downloads

  • This zip file contains the Kashflow and KashflowInvoice classes, and a test script which raises a sales invoice.
  • You may use this code as you see fit, but at your own risk.

Bonus tips

The biggest concern with integration is enforcing synchronisation between the systems. For maximum integrity, use the following rules:

  • Run Kashflow automation on Cron - inevitably there will be times you cannot connect to Kashflow, such as scheduled maintenance or temporary connectivity problems. If you run the integration in the background, your users will never know if there's a problem and you can handle them transparently.
  • Do one thing at a time - what happens if one API call works and then there's an error with a second? You'll have lost the results of the successful API call. Try to do one thing at a time, save everything you need and then move on to the next action.
  • Do Kashflow work late and use database transactions - if Kashflow succeeds but your subsequent code fails, you'll be left with unsynchronised data. Your system will think that it hasn't sent information to Kashflow, but Kashflow will have been updated!

Handle this by assuming that your Kashflow call will work, and doing all your database updates first. Do the Kashflow call as late as possible, and then you can easily rollback. The last thing to do is to store the result of the call such as an invoice id.

Did you find this useful?

If you found this article useful, I'd appreciate any or all of the following!

The Switchplane Team

Hey! We are Switchplane and we help businesses save time and money by building them custom software. This can be anything from a job management portal to a complex ecommerce solution. Want to find out more?

About Switchplane

Contact Us

Can we help with your project?

Get in touch

Join our Newsletter

Sign up to our monthly newsletter to keep up to date on the latest Switchplane and sector news.

You can unsubscribe at any time. View our Privacy Policy