Added some basic commands, ProvideTokenTrait and minor code updates

This commit is contained in:
Deon George 2024-08-12 20:55:41 +10:00
parent c9523f595b
commit 0cc4a217bd
13 changed files with 379 additions and 46 deletions

View File

@ -7,9 +7,9 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Intuit\Exceptions\{ConnectionIssueException,InvalidQueryResultException}; use Intuit\Exceptions\{ConnectionIssueException,InvalidQueryResultException,NotFoundException};
use Intuit\Models\{ProviderToken,Payment}; use Intuit\Models\{ProviderToken,Payment};
use Intuit\Response\{Customer,Invoice,ListList}; use Intuit\Response\{Customer,Invoice,ListList,Taxcode};
final class API final class API
{ {
@ -25,10 +25,14 @@ final class API
private const CURLOPT_HEADER = FALSE; private const CURLOPT_HEADER = FALSE;
private ProviderToken $token; private ProviderToken $token;
private string $url;
public function __construct(ProviderToken $token,bool $tryprod=FALSE) public function __construct(ProviderToken $token,bool $tryprod=FALSE)
{ {
$this->url = (config('app.env') == 'local' && ! $tryprod) ? 'https://sandbox-quickbooks.api.intuit.com' : 'https://quickbooks.api.intuit.com'; $this->url = ((config('app.env') === 'local') && (! $tryprod))
? 'https://sandbox-quickbooks.api.intuit.com'
: 'https://quickbooks.api.intuit.com';
$this->token = $token; $this->token = $token;
Log::debug(sprintf('%s:Intuit API for id [%s]',static::LOGKEY,$token->realm_id)); Log::debug(sprintf('%s:Intuit API for id [%s]',static::LOGKEY,$token->realm_id));
@ -36,9 +40,17 @@ final class API
/* STATIC */ /* STATIC */
/**
* URL to get log into Quickbooks
*
* @param bool $tryprod
* @return string
*/
public static function url(bool $tryprod=FALSE): string public static function url(bool $tryprod=FALSE): string
{ {
return (config('app.env') == 'local' && ! $tryprod) ? 'https://app.sandbox.qbo.intuit.com/app' : 'https://app.qbo.intuit.com/app'; return ((config('app.env') === 'local') && (! $tryprod))
? 'https://app.sandbox.qbo.intuit.com/app'
: 'https://app.qbo.intuit.com/app';
} }
/** /**
@ -50,7 +62,7 @@ final class API
private function convertHeaders(array $header): array private function convertHeaders(array $header): array
{ {
return collect($header) return collect($header)
->map(function($value,$key) { return sprintf('%s:%s',$key,$value); }) ->map(fn($value,$key)=>sprintf('%s:%s',$key,$value))
->values() ->values()
->toArray(); ->toArray();
} }
@ -63,7 +75,7 @@ final class API
* @return object|array * @return object|array
* @throws \Exception * @throws \Exception
*/ */
private function execute(string $path,array $parameters=[]) private function execute(string $path,array $parameters=[],string $query=NULL): mixed
{ {
$url = sprintf('%s/%s/company/%s/%s',$this->url,self::VERSION,$this->token->realm_id,$path); $url = sprintf('%s/%s/company/%s/%s',$this->url,self::VERSION,$this->token->realm_id,$path);
@ -163,9 +175,41 @@ final class API
} }
}); });
switch ($path) {
case 'query':
if (! $result->QueryResponse) {
Log::debug(sprintf('%s:Query response malformed',self::LOGKEY),['parameters'=>$parameters,'x'=>$x]);
throw new InvalidQueryResultException(sprintf('%s:Query response malformed',self::LOGKEY));
}
if (! object_get($result->QueryResponse,$query))
throw new NotFoundException(sprintf('%s:Query returned no results',self::LOGKEY));
return $result->QueryResponse;
}
return $result; return $result;
} }
/**
* Find a customer by their email address
*
* @param string $id
* @param array $parameters
* @return Customer
* @throws InvalidQueryResultException
*/
public function getAccountQuery(string $id,array $parameters=[]): Customer
{
Log::debug(sprintf('%s:Get a specific account [%s]',static::LOGKEY,$id));
$table = 'Customer';
$parameters['query'] = sprintf("select * from %s where Id='%s'",$table,$id);
$result = object_get($this->execute('query',$parameters,$table),$table);
return new Customer(array_pop($result));
}
/** /**
* Get a list of our classes * Get a list of our classes
* *
@ -182,28 +226,6 @@ final class API
return new ListList($this->execute('query',$parameters),$key); return new ListList($this->execute('query',$parameters),$key);
} }
/**
* Find a customer by their email address
*
* @param string $id
* @param array $parameters
* @return Customer
* @throws InvalidQueryResultException
*/
public function getAccountQuery(string $id,array $parameters=[]): Customer
{
Log::debug(sprintf('%s:Get a specific account [%s]',static::LOGKEY,$id));
$parameters['query'] = sprintf("select * from Customer where PrimaryEmailAddr='%s'",$id);
$x = $this->execute('query',$parameters);
if ((! $x->QueryResponse) || (! object_get($x->QueryResponse,'Customer')) || (count($x->QueryResponse->Customer) !== 1))
throw new InvalidQueryResultException(sprintf('%s:Query response malformed',self::LOGKEY));
return new Customer($x->QueryResponse);
}
/** /**
* Get a specific customer record * Get a specific customer record
* *
@ -247,14 +269,11 @@ final class API
{ {
Log::debug(sprintf('%s:Get a specific invoice [%s]',static::LOGKEY,$id)); Log::debug(sprintf('%s:Get a specific invoice [%s]',static::LOGKEY,$id));
$parameters['query'] = sprintf("select * from Invoice where DocNumber='%s'",$id); $table = 'Invoice';
$parameters['query'] = sprintf("select * from %s where DocNumber='%s'",$table,$id);
$result = object_get($this->execute('query',$parameters,$table),$table);
$x = $this->execute('query',$parameters); return new Invoice(array_pop($result));
if ((! $x->QueryResponse) || (! object_get($x->QueryResponse,'Invoice')) || (count($x->QueryResponse->Invoice) !== 1))
throw new InvalidQueryResultException(sprintf('%s:Query response malformed [%s]',self::LOGKEY,serialize($x)));
return new Invoice($x->QueryResponse);
} }
/** /**
@ -326,7 +345,26 @@ final class API
} }
/** /**
* Get a list of our invoices * Find an taxcode by its ID
*
* @param string $id
* @param array $parameters
* @return Taxcode
* @throws InvalidQueryResultException
*/
public function getTaxCodeQuery(string $id,array $parameters=[]): Taxcode
{
Log::debug(sprintf('%s:Get a specific invoice [%s]',static::LOGKEY,$id));
$table = 'TaxCode';
$parameters['query'] = sprintf("select * from %s where Id='%s'",$table,$id);
$result = object_get($this->execute('query',$parameters,$table),$table);
return new Taxcode(array_pop($result));
}
/**
* Get a list of our tax codes
* *
* @param array $parameters * @param array $parameters
* @return ListList * @return ListList
@ -336,9 +374,9 @@ final class API
{ {
Log::debug(sprintf('%s:Get a list of taxes',static::LOGKEY)); Log::debug(sprintf('%s:Get a list of taxes',static::LOGKEY));
$key = 'TaxCode'; $key = 'TaxCode';
$parameters['query'] = 'select * from Taxcode'; $parameters['query'] = 'select * from TaxCode';
return new ListList($this->execute('query',$parameters),$key); return new ListList($this->execute('query',$parameters,$key),$key);
} }
/** /**

View File

@ -0,0 +1,56 @@
<?php
namespace Intuit\Commands;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Console\Command;
use Intuit\Exceptions\ConnectionIssueException;
use Intuit\Exceptions\NotFoundException;
use Intuit\Traits\ProviderTokenTrait;
class AccountGet extends Command
{
use ProviderTokenTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'intuit:account:get'
.' {id : Account ID}'
.' {user? : User Email}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get an account from quickbooks';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$to = $this->providerToken($this->argument('user'));
try {
dump($to->API()->getAccountQuery($this->argument('id')));
} catch (ConnectException|ConnectionIssueException $e) {
$this->error($e->getMessage());
return self::FAILURE;
} catch (NotFoundException $e) {
$this->error('Nothing found');
return self::FAILURE;
}
return self::SUCCESS;
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace Intuit\Commands;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Console\Command;
use Intuit\Exceptions\ConnectionIssueException;
use Intuit\Exceptions\NotFoundException;
use Intuit\Traits\ProviderTokenTrait;
class InvoiceGet extends Command
{
use ProviderTokenTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'intuit:invoice:get'
.' {id : Invoice ID}'
.' {user? : User Email}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get an invoice from the quickbooks';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$to = $this->providerToken($this->argument('user'));
try {
dump($to->API()->getInvoiceQuery($this->argument('id')));
} catch (ConnectException|ConnectionIssueException $e) {
$this->error($e->getMessage());
return self::FAILURE;
} catch (NotFoundException $e) {
$this->error('Nothing found');
return self::FAILURE;
}
return self::SUCCESS;
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace Intuit\Commands;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Console\Command;
use Intuit\Exceptions\ConnectionIssueException;
use Intuit\Exceptions\NotFoundException;
use Intuit\Traits\ProviderTokenTrait;
use App\Jobs\AccountingPaymentSync as Job;
class PaymentGet extends Command
{
use ProviderTokenTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'intuit:payment:get'
.' {id : Payment ID}'
.' {user? : User Email}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get a payment from the accounting provider';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$to = $this->providerToken($this->argument('user'));
try {
dd($to->API()->getPayment($this->argument('id')));
} catch (ConnectException|ConnectionIssueException $e) {
$this->error($e->getMessage());
return self::FAILURE;
} catch (NotFoundException $e) {
$this->error('Nothing found');
return self::FAILURE;
}
if ($acc)
Job::dispatchSync($to,$acc);
return self::SUCCESS;
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace Intuit\Commands;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Console\Command;
use Intuit\Exceptions\ConnectionIssueException;
use Intuit\Exceptions\NotFoundException;
use Intuit\Traits\ProviderTokenTrait;
class TaxCodeGet extends Command
{
use ProviderTokenTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'intuit:taxcode:get'
.' {id : Taxcode ID}'
.' {user? : User Email}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get the defined tax codes from the accounting provider';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$to = $this->providerToken($this->argument('user'));
try {
$result = $to->API()->getTaxCodeQuery($this->argument('id'));
dd($result,$result->getTaxRateRef());
} catch (ConnectException|ConnectionIssueException $e) {
$this->error($e->getMessage());
return self::FAILURE;
} catch (NotFoundException $e) {
$this->error('Nothing found');
return self::FAILURE;
}
return self::SUCCESS;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Intuit\Exceptions;
use Exception;
class NotFoundException extends Exception
{
}

View File

@ -0,0 +1,9 @@
<?php
namespace Intuit\Exceptions;
use Exception;
class NotTokenException extends Exception
{
}

View File

@ -4,6 +4,7 @@ namespace Intuit\Providers;
use Illuminate\Routing\Router; use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Intuit\Commands\{AccountGet,InvoiceGet,PaymentGet,TaxCodeGet};
/** /**
* Class IntuitServiceProvider. * Class IntuitServiceProvider.
@ -20,6 +21,13 @@ class IntuitServiceProvider extends ServiceProvider
public function boot(Router $router) public function boot(Router $router)
{ {
$this->mergeConfigFrom($this->_path.'/config/intuit.php','intuit'); $this->mergeConfigFrom($this->_path.'/config/intuit.php','intuit');
$this->commands([
AccountGet::class,
InvoiceGet::class,
PaymentGet::class,
TaxCodeGet::class,
]);
} }
/** /**
@ -29,8 +37,7 @@ class IntuitServiceProvider extends ServiceProvider
*/ */
public function register() public function register()
{ {
if (! $this->_path) { if (! $this->_path)
$this->_path = realpath(__DIR__.'/../../src'); $this->_path = realpath(__DIR__.'/../../src');
}
} }
} }

View File

@ -55,8 +55,8 @@ abstract class Base implements \JsonSerializable
* @param mixed $value * @param mixed $value
* @return mixed * @return mixed
*/ */
public function search(string $key, mixed $value): mixed public function search(string $key,mixed $value): mixed
{ {
return $this->_data->search(function($item) use ($key,$value) { return $item->{$key} == $value; }); return $this->_data->search(fn($item)=>$item->{$key}===$value);
} }
} }

View File

@ -18,6 +18,6 @@ class Customer extends Base
if (object_get($response,'time')) if (object_get($response,'time'))
unset($response->time); unset($response->time);
$this->_model = new CustomerModel((array)$response->Customer); $this->_model = new CustomerModel((array)$response);
} }
} }

View File

@ -18,6 +18,6 @@ class Invoice extends Base
if (object_get($response,'time')) if (object_get($response,'time'))
unset($response->time); unset($response->time);
$this->_model = new InvoiceModel((array)$response->Invoice); $this->_model = new InvoiceModel((array)$response);
} }
} }

View File

@ -2,7 +2,8 @@
namespace Intuit\Response; namespace Intuit\Response;
use Intuit\Models\Tax as TaxModel; use Illuminate\Support\Collection;
use Intuit\Models\Taxcode as TaxcodeModel;
/** /**
* This is an Invoice Intuit Response to API calls * This is an Invoice Intuit Response to API calls
@ -18,6 +19,12 @@ class Taxcode extends Base
if (object_get($response,'time')) if (object_get($response,'time'))
unset($response->time); unset($response->time);
$this->_model = new TaxModel((array)$response->Tax); $this->_model = new TaxcodeModel((array)$response);
}
public function getTaxRateRef(): Collection
{
return collect($this->SalesTaxRateList->TaxRateDetail)
->pluck('TaxRateRef.value');
} }
} }

View File

@ -0,0 +1,33 @@
<?php
namespace Intuit\Traits;
use App\Models\{ProviderOauth,ProviderToken,User};
use Intuit\Exceptions\NotTokenException;
/**
* Return a provider token for API calls
*/
trait ProviderTokenTrait
{
private const provider = 'intuit';
/**
* Return a provider token to use for an API call
*
* @return ProviderToken
*/
protected function providerToken(string $user=NULL): ProviderToken
{
$uo = User::where('email',$user ?: config('osb.admin'))
->sole();
$so = ProviderOauth::where('name',self::provider)
->sole();
if (! ($to=$so->token($uo)))
throw new NotTokenException(sprintf('Unknown Tokens for [%s]',$uo->email));
return $to;
}
}