Skip to content

Instantly share code, notes, and snippets.

@dansleboby
Created February 17, 2018 08:17
Show Gist options
  • Save dansleboby/0abad06069a34fe8902e26e971511065 to your computer and use it in GitHub Desktop.
Save dansleboby/0abad06069a34fe8902e26e971511065 to your computer and use it in GitHub Desktop.
Little script to sync camscanner with Invoice Ninja Expenses
<?php
/*
Little script to sync camscanner with Invoice Ninja Expenses
-> How to use <-
1. create composer.json and run an update to get curl helper
2. Set 2 variables of invoice ninja
3. run php index.php
4. You will get an url https://api.intsig.net/qr_login/image?qrl_id=XXXXXXXXXXXXXXXX you need to open this in browser and scan with app to login in script
5. Enjoy!
-> Camscanner naming convention <-
YYYY-MM-DD_Vendor name_Amount_method payment
Ex: 2018-02-17_Wal-Mart_125.25_visa
This will add Wal-Mart as vendor if not exists and save the details of payments and attach pictures.
For payments method please update $payments_type there no api to fetch
-> Help <-
Just comment I will do my best to answer :)
composer.json
{
"require": {
"mervick/curl-helper": "^1.1"
}
}
*/
require "vendor/autoload.php";
$invoiceninja_api = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";//base path of invoiceninja self-hosted or sub-domain of hosted solution
$invoiceninja_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";//Api token
//Billing
echo "Fetch expenses...\n";
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/expenses?per_page=500")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token])
->exec();
$expenses = [];
foreach($response['data']['data'] as $data)
$expenses[] = $data['private_notes'];
echo "Fetch vendors...\n";
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/vendors?per_page=500")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token])
->exec();
$vendors = [];
foreach($response['data']['data'] as $data)
$vendors[$data['id']] = $data['name'];
echo "Fetch expenses cat....\n";
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/expense_categories?per_page=500")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token])
->exec();
$expense_categories = [];
foreach($response['data']['data'] as $data)
$expense_categories[$data['id']] = $data['name'];
echo "Payments type...\n";
$payments_type = [6 => 'visa', 3 => 'cash', 14 => 'Paypal'];
//Because I am lasy
echo "Flip...\n";
$vendors = array_flip($vendors);
$expense_categories = array_flip($expense_categories);
$payments_type = array_flip($payments_type);
function addExpenses($data) {
global $vendors, $expense_categories, $payments_type;
if(!array_key_exists($data['vendor_name'], $vendors)) {
//Create Vendors if not exists
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/vendors")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token, 'Content-Type' => CurlHelper::MIME_X_WWW_FORM])
->setPostFields([
'name' => $data['vendor_name']
])
->exec();
$vendors[$data['vendor_name']] = $response['data']['data']['id'];
}
$vendor_id = $vendors[$data['vendor_name']];
$vendor_name = $data['vendor_name'];
if(!array_key_exists($data['expense_categories_name'], $expense_categories)) {
//Create expense_categories if not exits
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/expense_categories")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token, 'Content-Type' => CurlHelper::MIME_X_WWW_FORM])
->setPostFields([
'name' => $data['expense_categories_name']
])
->exec();
$expense_categories[$data['expense_categories_name']] = $response['data']['data']['id'];
}
$expense_categories_id = $expense_categories[$data['expense_categories_name']];
$expense_categories_name = $data['expense_categories_name'];
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/expenses")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token, 'Content-Type' => CurlHelper::MIME_X_WWW_FORM])
->setPostFields([
'vendor_id' => $vendor_id,
'vendor_name' => $vendor_name,
'expense_category_id' => $expense_categories_id,
'expense_category_name' => $expense_categories_name,
'amount' => $data['amount'],
'expense_date' => $data['date'],
'should_be_invoiced' => '0',
'mark_paid' => '1',
'payment_type_id' => $payments_type[$data['payment']],
'payment_date' => $data['date'],
'invoice_documents' => '0',
'private_notes' => $data['id']
])
->exec();
$expense_id = $response['data']['data']['id'];
foreach($data['files'] as $file) {
$response = CurlHelper::factory("https://$invoiceninja_api/api/v1/documents")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-Ninja-Token' => $invoiceninja_token, 'Content-Type' => CurlHelper::MIME_FORM_DATA])
->setPostFields([
'expense_id' => $expense_id,
'name' => $file['name'],
'type' => $file['type']
])
->putFile('file', $file['path'])
->exec();
$document_id = $response['data']['data']['id'];
}
return is_numeric($expense_id) && is_numeric($document_id);
}
//Get login QR
$response = CurlHelper::factory("https://www.camscanner.com/user/qrlogin_init")
->setCookieFile('cookies.txt')
->exec();
$qrl_id = json_decode($response['data']['data'])->qrl_id;
echo "https://api.intsig.net/qr_login/image?qrl_id=$qrl_id\n";
//Check if QR was scanned
echo "CHECK...\n";
do {
echo ".";
$response = CurlHelper::factory("https://www.camscanner.com/user/qrlogin_query?qrl_id=$qrl_id")
->setCookieFile('cookies.txt')
->exec();
$data = json_decode($response['data']['data']);
if(property_exists($data, 'token')) {
$token = $data->token;
echo "\nGrep token\n";
}
sleep(1);
} while ($data->status != 3);
//Make login with token
echo "\nLogin... [$token]\n";
$response = CurlHelper::factory("https://www.camscanner.com/user/login")
->setHeaders(['Content-Type' => CurlHelper::MIME_X_WWW_FORM, 'X-Requested-With' => 'XMLHttpRequest'])
->setPostFields(['token' => $token, 'act' => 'submit', 'type' => 'qrlogin'])
->setCookieFile('cookies.txt')
->exec();
if(!empty($response['data'])) {
echo "Data...\n";
$response = CurlHelper::factory("https://www.camscanner.com/doc/list")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest'])
->setCookieFile('cookies.txt')
->exec();
$files = $response['data']['data']['list'];
$server = $response['data']['data']['server'];
$data = [];
foreach($files as $file) {
if(in_array($file['doc_id'], $expenses)) {
echo "Already in DB...\n";
continue;
}
$tmp = [];
if(preg_match("#^[0-9]{4}-[0-9]{2}-[0-9]{2}.*#", $file['title']) && isset($file['tag'])) {
$parse = explode('_', $file['title']);
if(count($parse) == 4)
list($date, $vendor_name, $amount, $type) = $parse;
else if(count($parse) == 3){
list($date, $vendor_name, $amount) = $parse;
$type = 'visa';
} else {
echo "ERROR PARSE: ".$file['title']."\n";
continue;
}
$expense_categories_name = $file['tag'];
$tmp = [
'id' => $file['doc_id'],
'expense_categories_name' => $expense_categories_name,
'vendor_name' => $vendor_name,
'amount' => $amount,
'payment' => $type,
'date' => $date,
'files' => [],
];
if($file['c'] > 1) {
//Need to fetch
echo "Fetch page...\n";
$response = CurlHelper::factory("https://www.camscanner.com/doc/pagelist")
->setHeaders(['X-Requested-With' => 'XMLHttpRequest'])
->setPostFields(['doc_id' => $tmp['id']])
->setCookieFile('cookies.txt')
->exec();
$pages = $response['data']['data'];
foreach($pages as $page) {
if(!file_exists($page['page_id'].".jpg")) {
echo "Down :".$page['page_id']."\n";
$response = CurlHelper::factory($page['page_photo'])
->setCookieFile('cookies.txt')
->exec();
file_put_contents($page['page_id'].".jpg", $response['content']);
} else {
echo "File exists: ".$page['page_id'].".jpg\n";
}
$tmp['files'][] = ['name' => $page['page_id'].".jpg", 'type' => 'jpg', 'path' => $page['page_id'].".jpg"];
}
} else {
if(!file_exists($file['p'].'.jpg')) {
echo "Down :".$file['p']."\n";
$response = CurlHelper::factory($server.$file['p'].'.jpg')
->setCookieFile('cookies.txt')
->exec();
file_put_contents($file['p'].'.jpg', $response['content']);
} else {
echo "File exists: ".$file['p'].'.jpg'."\n";
}
$tmp['files'][0] = ['name' => $file['p'].'.jpg', 'type' => 'jpg', 'path' => $file['p'].'.jpg'];
}
echo "Push to billing...\n";
$res = addExpenses($tmp);
if($res) {
echo "Success\n";
} else {
echo "Failed\n";
print_r($tmp);
print_r($file);
die();
}
} else {
/*echo "\n\n\n!!! ERROR !!!!\n";
print_r($file);
echo "\n\n\n";*/
echo "Error bad title: ".$file['title']."\n";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment