Initial integration with Quickbooks
This commit is contained in:
269
app/Console/Commands/QuickAccounts.php
Normal file
269
app/Console/Commands/QuickAccounts.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\External\Accounting\Quickbooks;
|
||||
use App\Models\Account;
|
||||
use App\Models\External\Integrations;
|
||||
use QuickBooksOnline\API\Data\IPPEmailAddress;
|
||||
use QuickBooksOnline\API\Data\IPPPhysicalAddress;
|
||||
|
||||
class QuickAccounts extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'external:sync:accounts {--m|match : Match Display Name}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Sync Account numbers with External Sources';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
DB::listen(function($query) {
|
||||
Log::debug('- SQL',['sql'=>$query->sql,'binding'=>$query->bindings]);
|
||||
});
|
||||
|
||||
foreach (Integrations::active()->type('ACCOUNTING')->get() as $into)
|
||||
{
|
||||
switch ($into->name)
|
||||
{
|
||||
case 'quickbooks':
|
||||
$api = new Quickbooks($into->user);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('No handler for: ',$into-name);
|
||||
}
|
||||
|
||||
foreach ($api->getCustomers(TRUE) as $r)
|
||||
{
|
||||
$this->info(sprintf('Checking [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
|
||||
if ($r->Notes == 'Cash Only')
|
||||
{
|
||||
$this->warn(sprintf('Skipping [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->option('match') AND (! $r->CompanyName AND (! $r->FamilyName AND ! $r->GivenName)))
|
||||
{
|
||||
$this->error(sprintf('No COMPANY or PERSONAL details for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->option('match')) {
|
||||
$ao = Account::where('company',$r->DisplayName);
|
||||
|
||||
if (! $ao->count()) {
|
||||
$uo = User::where('lastname',$r->FamilyName);
|
||||
|
||||
if ($r->GivenName)
|
||||
$uo->where('firstname',$r->GivenName);
|
||||
|
||||
if ($uo->count() > 1 OR (! $uo->count()))
|
||||
{
|
||||
$this->error(sprintf('No SINGLE Users matched for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$uo = $uo->first();
|
||||
$ao = $uo->accounts->where('active',TRUE);
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($r->CompanyName) {
|
||||
$ao = Account::where('company',$this->option('match') ? $r->DisplayName : $r->CompanyName);
|
||||
} else {
|
||||
$uo = User::where('lastname',$r->FamilyName);
|
||||
|
||||
if ($r->GivenName)
|
||||
$uo->where('firstname',$r->GivenName);
|
||||
|
||||
if ($uo->count() > 1 OR (! $uo->count()))
|
||||
{
|
||||
$this->error(sprintf('No SINGLE matched for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$uo = $uo->first();
|
||||
$ao = $uo->accounts->where('active',TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (! $ao->count())
|
||||
{
|
||||
$this->error(sprintf('No Accounts matched for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($ao->count() > 1)
|
||||
{
|
||||
$this->error(sprintf('Too Many Accounts (%s) matched for [%s] (%s)',$ao->count(),$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$ao = $ao->first();
|
||||
|
||||
// If we are matching on DisplayName, make sure the account is updated correct for Business or Personal Accounts
|
||||
$oldr = clone $r;
|
||||
|
||||
// @NOTE: This overwrites the ABN if it exists.
|
||||
if ($r->PrimaryTaxIdentifier)
|
||||
{
|
||||
$this->warn(sprintf('ABN Overwrite for (%s)',$r->DisplayName));
|
||||
}
|
||||
|
||||
switch ($ao->type)
|
||||
{
|
||||
case 'Business':
|
||||
$r->CompanyName = $ao->company;
|
||||
$r->ResaleNum = $ao->AccountId;
|
||||
$r->SalesTermRef = '7'; // @todo
|
||||
|
||||
if ($ao->first_name)
|
||||
$r->GivenName = chop($ao->user->firstname); // @todo shouldnt be required
|
||||
if ($ao->last_name)
|
||||
$r->FamilyName = $ao->user->lastname;
|
||||
|
||||
if ($ao->address1)
|
||||
{
|
||||
if (! $r->BillAddr)
|
||||
$r->BillAddr = new IPPPhysicalAddress;
|
||||
|
||||
$r->BillAddr->Line1 = $ao->user->address1;
|
||||
$r->BillAddr->Line2 = $ao->user->address2;
|
||||
$r->BillAddr->City = $ao->user->city;
|
||||
$r->BillAddr->CountrySubDivisionCode = strtoupper($ao->user->state);
|
||||
$r->BillAddr->PostalCode = $ao->user->postcode;
|
||||
$r->BillAddr->Country = 'Australia'; // @todo
|
||||
|
||||
//$r->ShipAddr = $r->BillAddr;
|
||||
}
|
||||
|
||||
if ($ao->email) {
|
||||
if (! $r->PrimaryEmailAddr)
|
||||
$r->PrimaryEmailAddr = new IPPEmailAddress;
|
||||
|
||||
$r->PrimaryEmailAddr->Address = $ao->user->email;
|
||||
$r->PreferredDeliveryMethod = 'Email';
|
||||
}
|
||||
|
||||
if (! $r->Balance)
|
||||
$r->Active = $ao->active ? 'true' : 'false';
|
||||
|
||||
break;
|
||||
|
||||
case 'Private':
|
||||
$r->CompanyName = NULL;
|
||||
$r->DisplayName = sprintf('%s %s',$ao->user->lastname,$ao->user->firstname);
|
||||
$r->ResaleNum = $ao->AccountId;
|
||||
$r->SalesTermRef = '7'; // @todo
|
||||
|
||||
if ($ao->first_name)
|
||||
$r->GivenName = chop($ao->user->firstname); // @todo shouldnt be required
|
||||
if ($ao->last_name)
|
||||
$r->FamilyName = $ao->user->lastname;
|
||||
|
||||
if ($ao->address1)
|
||||
{
|
||||
if (! $r->BillAddr)
|
||||
$r->BillAddr = new IPPPhysicalAddress;
|
||||
|
||||
$r->BillAddr->Line1 = $ao->user->address1;
|
||||
$r->BillAddr->Line2 = $ao->user->address2;
|
||||
$r->BillAddr->City = $ao->user->city;
|
||||
$r->BillAddr->CountrySubDivisionCode = strtoupper($ao->user->state);
|
||||
$r->BillAddr->PostalCode = $ao->user->postcode;
|
||||
$r->BillAddr->Country = 'Australia'; // @todo
|
||||
|
||||
//$r->ShipAddr = $r->BillAddr;
|
||||
}
|
||||
|
||||
if ($ao->email) {
|
||||
if (! $r->PrimaryEmailAddr)
|
||||
$r->PrimaryEmailAddr = new IPPEmailAddress;
|
||||
|
||||
$r->PrimaryEmailAddr->Address = $ao->user->email;
|
||||
$r->PreferredDeliveryMethod = 'Email';
|
||||
}
|
||||
|
||||
if (! $r->Balance)
|
||||
$r->Active = $ao->active ? 'true' : 'false';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('Unhandled account type: '.$ao->type);
|
||||
|
||||
}
|
||||
|
||||
// If something changed, lets update it.
|
||||
if (count(array_diff_assoc(object_to_array($r,FALSE),object_to_array($oldr,FALSE))))
|
||||
{
|
||||
$api->updateCustomer($r,[]);
|
||||
}
|
||||
|
||||
// If external integration doesnt exist, lets create it.
|
||||
if (! $ao->ExternalAccounting($into))
|
||||
{
|
||||
$ao->external()->attach([$into->id=>['site_id'=>1,'link'=>$r->Id]]); // @todo site_id
|
||||
}
|
||||
|
||||
// If the integration ID doesnt exist in the integration source, add it.
|
||||
if (! $r->ResaleNum)
|
||||
{
|
||||
$api->updateCustomer($r,['ResaleNum'=>$ao->AccountId]);
|
||||
}
|
||||
|
||||
// If integration exist, double check the numbers match
|
||||
if ($r->ResaleNum != $ao->AccountId) {
|
||||
$this->warn(sprintf('Integration ID Mismatch AID [%s] ID [%s]',$ao->id,$r->Id));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function object_to_array($object,$encode=TRUE)
|
||||
{
|
||||
// For child arrays, we just encode
|
||||
if ($encode)
|
||||
return json_encode($object);
|
||||
|
||||
if (is_object($object)) {
|
||||
return array_map(__FUNCTION__,get_object_vars($object));
|
||||
} else if (is_array($object)) {
|
||||
return array_map(__FUNCTION__,$object);
|
||||
} else {
|
||||
return $object;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user