Fetches billing information from AWS on demand and creates a Xero invoice. Pull requests welcome, we'd love to support more services. At the moment it makes extensive use of the open source community managed xero-php SDK for PHP as well as the AWS SDK for PHP 3.x to query the AWS Cost Explorer.
- You have an AWS account with AWS Organizations enabled
- You have also enabled the AWS Cost Explorer
- You have enabled IAM user access to Billing Information (you need to be the account root user)
- You have an IAM user on your main account with access to the Cost Explorer API
- You have a Xero account
- You have created a user on your Xero account for use by the application
- You have created a key pair for a Xero app
- You have created and registered a private app on the Xero Developer Portal
- Clone this repository (to somewhere sane, probably /opt on a *nix system)
- Install PHP for your system (make sure you also have the cURL extension)
- Install composer for PHP
- In the cloned directory run
composer install
to install the dependencies
You need to create two files:
config.json
accounts.json
These are the recommended filenames for these files and both filenames are ignored by Git. However, you may choose to call them anything and also have multiple sets if config and accounts files for different billing scenarios. See the documentation below for details. In any case, the contents of config and accounts files should be as follows:
/*
* Gitignored config JSON file containing all our secrets.
* Note, you need to remove this doc block and the inline comments if you use this as a template.
*/
{
'aws' : {
'key' : 'ABCDEFGHIJKLMNOPQRST', // the key belonging to an IAM user with access to billing reports
'secret' : 'abCdEFghiJkLmnOPQrSTuvwXyz123456787', // the secret associated with the above key
'region' : 'eu-west-1', // the region your S3 billing bucket is in
'accountsFile' : 'accounts' // the filename of the file containing your accounts to bill data (see below)
},
// General accountancy settings
'general' : {
'costPadding' : 1.02, // set to 1 to disable, we pad by 2% because AWS convert to GBP with Visa rate
'includeTax' : false, // flag for if we should include sales tax in rebilling or not
'defaultReference' : 'AWS rebilling' // optional default reference to add to all invoices without a reference (see below for per-account references)
},
// Provider settings
'provider' : {
'name' : 'xero', // Selected accountancy provider (currently only FreeAgent)
'incomeCategory' : 'XXX', // the Xero accounting category code, remove if not required
'trackingCategory' : 'Department', // optional tracking category - if you provide one, you must also provide the option to use:
'trackingCategoryOption' : 'Systems', // optional tracking option to apply to line items
'defaultStatus' : 'SUBMITTED', // optional invoice status to use (defaults to 'DRAFT')
'oauth' : {
'client': {
'id': 'abcfdefghijklmnop', // your FreeAgent app OAuth identifier
'secret': '123ghjk4567jkhabbja', // your FreeAgent app OAuth secret
'rsaKey': 'keyfilename.pem' // filename of your private key, assumes repo / app root is location
}
}
}
}
In this example the accounts data file is accounts.json
because we have specified 'accounts
' as the filename above under our AWS config. If we had placed foo
in the accountsFile
option above, this file would be named foo.json
.
/*
* Gitignored list of accounts to generate invoices for.
*
* Xero uses ISO currency codes: https://www.xe.com/iso4217.php
*
* AWS : the AWS account number to bill or null if not an Organizations account
* contact : the Xero GUID of the contact record for the same organisation
* currency : the 3 letter ISO currency code
* VAT : either true or false, no need to calculate VAT, Xero does this
* EU : boolean to say whether organisation is EC area or not
* reference : optional reference, e.g. a PO number, to be included for this account
*
* Note, you need to remove this doc block and the inline comments if you use this as a template.
*/
{
'Customer1' : {
'AWS' : 'XXXXXXXXXXXX',
'contact' : '1abc234a-b56c-123a-1a23-423b9729e7a9',
'currency' : 'GBP', // billing in GBP, so we will run a currency conversion
'VAT' : true, // customer will be charged VAT at at the 'CAPEXOUTPUT2' Xero rate (currently 20%)
'EU' : false, // customer is not in the EC
'reference' : 'PO: 12345678' // customer provided PO number
},
'Customer2' : {
'AWS' : 'XXXXXXXXiXXXX',
'contact' : '2def567x-b56c-123a-1a23-423b9729e7a9',
'currency' : 'USD',
'VAT' : false, // customer will not be charged VAT
'EU' : true // invoice items will be marked as EC for VAT purposes
}
}
Once you've installed and configured Billder, the best way to run it is some kind of automated task, either from a continuous integration system (we use Jenkins for orchestration) or in cron on a *nix server. The command, if you cloned Billder to /opt as suggested above, will look something like this:
php -f /opt/billder/index.php config
A monthly crontab entry might be to run Billder on the second day of each month (you want to be sure AWS has had time to complete your data) at 01:00AM server time, and it would look like this:
0 1 2 * * root php -f /opt/billder/index.php config
Note the config
argument passed to our script, this is obligatory and it is the filename of our configuration file. By making it an argument, you can have multiple instances of Billder running for different AWS accounts with different config files. Our example assumes the config file is config.json
and so we pass config
as the filename to the script.
Billder also supports being passed a month to generate invoices for in the form of 'YYYY-MM', e.g. 2017-11
. If you do not pass it a month to process, it will automatically use last month, so if you are in November 2017 it will create invoices for October 2017 (2017-10
) by default. Passing Billder a month to process is as simple as this example, which will process June 2016:
php -f /opt/billder/index.php config 2016-06
And that's all there is to it!
If you wish to add your own accountancy software as a software provider to this base project, you can create a PR. The structure for multiple providers is not yet decided, this is not yet 'proper' object oriented PHP code, when it is we'll provide some classes you can extend and override.
Note, you can also add elements to config.json
and accounts.json
above, but please provide a patch for this README as well if you do.
PROVIDERNAME
will become the 'provider' element in the 'config' object in config.json
.
- Add a note to Xero invoices
- Assign line items to projects automatically (request raised with Xero about this, not currently supported by the API)
- Base currency configuration
- Other providers!