This is a very Simple FrontAccounting API. The concept of FA <=> POS integration is explained in this Forum Post.
Slim2 Hello World starter pack for FA.
Slim v2.64 based REST API for FA v2.4.x | Forum Post
Some basic integration functions needed to connect to another software. This resulted in creation of this REST API and contributed to the FrontAccounting team. It is based on the Slim Framework for PHP5. The database helpers defined in *.inc files in respective includes/db folders are used here.
A fully implemented FA <-> POS system set of features (not using SimpleAPI) are listed are at: http://www.cartbooks.com/frontaccounting-point-of-sale/
SimpleAPI GitHub Repo (Forum Post):
https://github.com/andresamayadiaz/FrontAccountingSimpleAPI
API Quick Start
- Just copy the files into the modules directory under a folder called api (hardcoded in the api files).
- Edit the file util.php and change the $company, $username and $password variables so you can test and then comment out the test lines for actual use. Use it at your own risk, to provide login from another software you need to send X_company, X_user and X_password headers in the request and the API will use those credentials, if they're wrong you will get a nice message telling Bad Login
- Do not use MultiViews in the Apache Config file which should have a stanza like the following one:
<IfModule mod_rewrite.c> <Location /modules/api/> Options -MultiViews RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L] </Location> </IfModule>
- Try to access the API, for example, try the Items Category List taken from the stock_category table, type this on your explorer: http://YOUR_FA_URL/modules/api/category/ ---> You will see a JSON with all you're items categories. If not check the util.php file. A sample output is here.
Error Codes implemented in SimpleAPI
- 200 OK
- 201 Create Response
- 400 Invalid table ID
- 403 Bad Login For Company
- 412 Field is required
- 500 Could Not Change Database Contents
Methods
NOTE: methods below that say "get list of all" are actually paginated. You must retrieve pages one at time by adding "?page=XX" to the end of the URL. The API is hard-coded to return 2 items per page.
Currently implemented are:
Type | Action | Function |
---|---|---|
Items | ||
GET | /inventory/ | Get list of All Inventory Items |
GET | /inventory/:id | Get details of Inventory Item = id |
POST | /inventory/ | Add inventory items |
PUT | /inventory/:id | Edit Inventory Item = id |
DELETE | /inventory/:id | Delete Inventory Item = id |
Inventory Movements (FA 2.3.x only) | ||
GET | /movementtypes/ | Get list of All Inventory Movement Types |
Inventory Locations | ||
GET | /locations/ | Get list of All Locations |
POST | /locations/ | Add Location |
Stock Adjustments | ||
POST | /stock/ | Add Stock Adjustment |
Item Categories | ||
GET | /category/ | Get list of All Item Categories |
GET | /category/:id | Get details of Item Category = id |
POST | /category/ | Add Item Category |
PUT | /category/:id | Edit Item Category = id |
DELETE | /category/:id | Delete Item Category = id |
Tax Types | ||
GET | /taxtypes/ | Get list of All Tax Types |
GET | /taxtypes/:id | Get details of Tax Type = id |
Tax Groups | ||
GET | /taxgroups/ | Get list of All Tax Groups |
Customers | ||
GET | /customers/ | Get list of All Customers |
GET | /customers/:id | Get details of Customer ID = id |
POST | /customers/ | Add Customer |
PUT | /customers/:id | Edit Customer ID = id |
DELETE | /customers/:id | Delete Customer ID = id |
GET | /customers/:id/branches/ | Get Branch list for Customer ID = id |
Suppliers | ||
GET | /suppliers/ | Get list of All Suppliers |
GET | /suppliers/:id | Get details of Supplier ID = id |
POST | /suppliers/ | Add Supplier |
PUT | /suppliers/:id | Edit Supplier ID = id |
DELETE | /suppliers/:id | Delete Supplier ID = id |
GET | /suppliers/:id/contacts/ | Get Contact list for Supplier ID = id |
Bank Accounts | ||
GET | /bankaccounts/ | Get list of Bank Accounts |
GET | /bankaccounts/:id | Get details of Bank Account ID = id |
POST | /bankaccounts/ | Add Bank Account |
PUT | /bankaccounts/:id | Edit Bank Account ID = id |
DELETE | /bankaccounts/:id | Delete Bank Account ID = id |
GL Accounts | ||
GET | /glaccounts/ | Get list of All GL Accounts |
GET | /glaccounts/:id | Get details of GL Account ID = id |
POST | /glaccounts/ | Add GL Account |
PUT | /glaccounts/:id | Edit GL Account ID = id |
DELETE | /glaccounts/:id | Delete GL Account ID = id |
GL Account Types | ||
GET | /glaccounttypes/ | Get list of GL Account Types |
Currencies | ||
GET | /currencies/ | Get list of All Currencies |
GET | /currencies/:id | Get details of Currency ID = id |
Exchange Rates | ||
GET | /exrates/:curr_abrev | Get Last Exchange Rate for Currency Abbreviation = curr_abrev |
Item Costs | ||
GET | /itemcosts/:id | Get cost of Item ID = id |
PUT | /itemcosts/:id | Edit cost of Item ID = id |
Fixed Assets | ||
GET | /assets/:id | Get details of Fixed Asset ID = id |
POST | /assets/ | Add Fixed Asset |
Asset Types | ||
GET | /assettypes/ | Get list of All Asset Types |
Sales Quotes (FA 2.3.x only) | ||
GET | /salesquotes/:id | Get Sales Quote ID = id |
POST | /salesquotes/ | Add Sales Quote - WIP |
Sales | ||
GET | /sales/:trans_no/:trans_type | Get Sales Header and Details for trans_no, trans_type |
POST | /sales/ | Add Sales Header and Details |
PUT | /sales/:trans_no/:trans_type | Edit Sales Header and Details for trans_no, trans_type |
DELETE | /sales/:branch_id/:uuid | Cancel Sales branch_id, uuid |
GET | /sales/:trans_type/ | Get All Sales Header and Details for trans_no |
Dimensions | ||
GET | /dimensions/ | Get list of All Dimensions |
GET | /dimensions/:ref | Get details of Dimension = ref |
POST | /dimensions/ | Add Dimension |
PUT | /dimensions/:ref | Edit Dimension = ref |
DELETE | /dimensions/:ref | Delete Dimension = ref |
Journals | ||
GET | /journal/ | Get list of All Journals |
GET | /journal/:type/:id | Get details of Journal type, id |
POST | /journal/ | Add Journal |
PUT | /journal/:id | Edit Journal ID = id |
DELETE | /journal/:type/:id | Delete Journal type, id |
Some of them have not been tested yet so be careful.
Sample Usage
Create a testslim.php file with the following contents and place it in the modules/api folder and execute it in a browser:
<?php // Usage: // http://www.mydomain.com/modules/api/testslim.php/hello/Alpha/Beta // Will output: // Hello, Alpha, Beta include_once ("Slim/Slim.php"); \Slim\Slim::registerAutoloader(); $app = new \Slim\Slim(); $app->get('/hello/:name/:name2', function ($nameone,$two) { echo "Hello, $nameone, $two"; }); $app->run(); ?>
Testing Access from external server
Extract the FA REST Bridge files into another server's webroot (or any folder path in it). Change the fabridge.php's constants with values in the first few lines to suit your FA server's access details).
Contents of fabridge.php:
<?php /* FrontAccounting Bridge Function Ref: http://singletonio.blogspot.in/2009/07/simple-php-rest-client-using-curl.html Author: Ap.Muthu Website: http://www.apmuthu.com Release Date: 2012-11-28 */ define("REST_URL", "http://www.mydomain.com/modules/api"); define("COMPANY_NO", "0"); define("REST_USER", "admin"); define("REST_PWD", "123456"); function fa_bridge($method="g", $action, $record="", $filter=false, $data=false) { $url = REST_URL . "/$action/$record"; if ($filter) $url .= "/$filter"; # headers and data (this is API dependent, some uses XML) $headers = array(); /* // optional headers $headers[] = "Accept: application/json"; $headers[] = "Content-Type: application/json"; */ $headers[] = "X-COMPANY: " . COMPANY_NO; $headers[] = "X-USER: " . REST_USER; $headers[] = "X-PASSWORD: " . REST_PWD; $handle = curl_init(); curl_setopt($handle, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_HEADER, 0); curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false); switch($method) { case 'g': break; case 'p': curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POSTFIELDS, $data); break; case 't': curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($handle, CURLOPT_POSTFIELDS, $data); break; case 'd': curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE'); break; } // grab URL and pass it to the variable and not browser ob_start(); curl_exec($handle); $content = ob_get_contents(); ob_end_clean(); $code = curl_getinfo($handle, CURLINFO_HTTP_CODE); // close cURL resource, and free up system resources curl_close($handle); $content = ($code == "200") ? json_decode($content, true) : false; return $content; } ?>
Contents of facurlrest.php file:
<?php // FrontAccounting Bridge REST Test Script // Author: Ap.Muthu // Website: www.apmuthu.com // Release Date: 2012-11-28 include_once "fabridge.php"; $method = isset($_GET['m']) ? $_GET['m'] : 'g'; // g, p, t, d => GET, POST, PUT, DELETE $action = isset($_GET['a']) ? $_GET['a'] : ''; $record = isset($_GET['r']) ? $_GET['r'] : ''; $filter = isset($_GET['f']) ? $_GET['f'] : false; // Sample Data for POST $data = json_encode(array( 'firstName'=> 'John', 'lastName'=> 'Doe' )); $data = http_build_query($data); $output = fa_bridge($method, $action, $record, $filter, $data); echo print_r($output, true); ?>
Now execute http://IP_OF_OTHER_SERVER/REST_PATH/facurlrest.php?a=category in a browser as an example to get all the category details and the output would contain all records and be like:
Array ( [0] => Array ( [category_id] => 1 [description] => Components [dflt_tax_type] => 1 [dflt_units] => each [dflt_mb_flag] => B [dflt_sales_act] => 4010 [dflt_cogs_act] => 5010 [dflt_inventory_act] => 1510 [dflt_adjustment_act] => 5040 [dflt_assembly_act] => 1530 [dflt_no_sale] => 0 ) [1] => Array ( [category_id] => 2 [description] => Charges [dflt_tax_type] => 1 [dflt_units] => each [dflt_mb_flag] => D [dflt_sales_act] => 4010 [dflt_cogs_act] => 5010 [dflt_inventory_act] => 1510 [dflt_adjustment_act] => 5040 [dflt_assembly_act] => 1530 [dflt_no_sale] => 0 ) [2] => Array ( [category_id] => 3 [description] => Systems [dflt_tax_type] => 1 [dflt_units] => each [dflt_mb_flag] => M [dflt_sales_act] => 4010 [dflt_cogs_act] => 5010 [dflt_inventory_act] => 1510 [dflt_adjustment_act] => 5040 [dflt_assembly_act] => 1530 [dflt_no_sale] => 0 ) [3] => Array ( [category_id] => 4 [description] => Services [dflt_tax_type] => 1 [dflt_units] => hrs [dflt_mb_flag] => D [dflt_sales_act] => 4010 [dflt_cogs_act] => 5010 [dflt_inventory_act] => 1510 [dflt_adjustment_act] => 5040 [dflt_assembly_act] => 1530 [dflt_no_sale] => 0 ) )
If a record number is specified we get the specific record. On appending &r=2 in the url and executing it, we get the details of the the Item Category 2 - the data is available as ASSOCiated and Index Numbered:
Array ( [0] => 2 [category_id] => 2 [1] => Charges [description] => Charges [2] => 1 [dflt_tax_type] => 1 [3] => each [dflt_units] => each [4] => D [dflt_mb_flag] => D [5] => 4010 [dflt_sales_act] => 4010 [6] => 5010 [dflt_cogs_act] => 5010 [7] => 1510 [dflt_inventory_act] => 1510 [8] => 5040 [dflt_adjustment_act] => 5040 [9] => 1530 [dflt_assembly_act] => 1530 [10] => 0 [dflt_dim1] => 0 [11] => 0 [dflt_dim2] => 0 [12] => 0 [inactive] => 0 [13] => 0 [dflt_no_sale] => 0 )
Example URIs for REST Access
- http://IP_OF_OTHER_SERVER/REST_PATH/facurlrest.php?a=category
- http://IP_OF_OTHER_SERVER/REST_PATH/facurlrest.php?a=category&r=1
- http://IP_OF_OTHER_SERVER/REST_PATH/facurlrest.php?a=locations
- http://IP_OF_OTHER_SERVER/REST_PATH/facurlrest.php?exrates&r=INR
If m=t (Edit), m=p (Add) or m=d (Delete) are used in the URL, then the $data array must have the field values set in the script accordingly. The actual field subscripts used in the $data array can be taken from the respective *.inc files included in the SimpleAPI module.
REST Clients
- PHP HTTP Client
- RESTful CRUD
- REST Client @GoogleCode
- PEST PHP REST Client
- PHP cURL REST Client - Used in this article
- Guzzle
- Tutorials - 1, 2
FA on CLI using bash
USERNAME=XXX PWDCODE=YYYY COMPANY=1 wget -q --save-cookies tmp/cookies$$.txt \ --keep-session-cookies \ --post-data 'user_name_entry_field=${USERNAME}&password=${PWDCODE}&company_login_name=${COMPANY}' \ --delete-after \ http://localhost/frontac24/index.php ## To get the Customer List using '''rep103.php''': wget -q --load-cookies tmp/cookies$$.txt \ -O - http://localhost/frontac24/reporting/rep103.php \ --post-data "PARAM_0=09/13/2014&PARAM_1=&PARAM_2=&PARAM_3=&PARAM_4=&PARAM_5=&PARAM_6=&PARAM_7=0&REP_ID=103" > /tmp/foo.pdf
Support and Contact
- Any question about this you can always contact the author Andres Amaya Diaz at andres.amaya.diaz@gmail.com