Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
e8b049a2e8 | |||
6741d95073 | |||
9d81824b52 | |||
0cc4a217bd | |||
c9523f595b | |||
947e1358b5 | |||
403d2168c1 | |||
b87550fae7 | |||
c35a439566 | |||
0c5ffdad2f | |||
600dfec536 | |||
dd82509008 | |||
2f75c7dd1f | |||
|
ffe70058ba | ||
|
2f1b34a806 | ||
|
4be82315c5 | ||
|
0076ecef31 | ||
|
179c96ca5d | ||
|
1d209fdbdc | ||
|
59302bd3e8 |
@ -1,23 +1,23 @@
|
||||
{
|
||||
"name": "leenooks/intuit",
|
||||
"description": "Intuit API",
|
||||
"keywords": ["laravel","leenooks","intuit"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Deon George",
|
||||
"email": "deon@leenooks.net"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"jenssegers/model": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Intuit\\": "src"
|
||||
}
|
||||
},
|
||||
"name": "leenooks/intuit",
|
||||
"description": "Intuit API",
|
||||
"keywords": ["laravel","leenooks","intuit"],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Deon George",
|
||||
"email": "deon@dege.au"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"jenssegers/model": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Intuit\\": "src"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
@ -25,5 +25,5 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
|
251
src/API.php
251
src/API.php
@ -2,12 +2,14 @@
|
||||
|
||||
namespace Intuit;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use Intuit\Models\ProviderToken;
|
||||
use Intuit\Response\{Customer,ListList};
|
||||
use Intuit\Exceptions\{ConnectionIssueException,InvalidQueryResultException,NotFoundException};
|
||||
use Intuit\Models\{ProviderToken,Payment};
|
||||
use Intuit\Response\{Customer,Invoice,ListList,Taxcode};
|
||||
|
||||
final class API
|
||||
{
|
||||
@ -23,15 +25,34 @@ final class API
|
||||
private const CURLOPT_HEADER = FALSE;
|
||||
|
||||
private ProviderToken $token;
|
||||
private string $url;
|
||||
|
||||
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;
|
||||
|
||||
Log::debug(sprintf('%s:Intuit API for id [%s]',static::LOGKEY,$token->realm_id));
|
||||
}
|
||||
|
||||
/* STATIC */
|
||||
|
||||
/**
|
||||
* URL to get log into Quickbooks
|
||||
*
|
||||
* @param bool $tryprod
|
||||
* @return 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';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an Array to Curl Headers
|
||||
*
|
||||
@ -41,7 +62,7 @@ final class API
|
||||
private function convertHeaders(array $header): array
|
||||
{
|
||||
return collect($header)
|
||||
->map(function($value,$key) { return sprintf('%s:%s',$key,$value); })
|
||||
->map(fn($value,$key)=>sprintf('%s:%s',$key,$value))
|
||||
->values()
|
||||
->toArray();
|
||||
}
|
||||
@ -54,7 +75,7 @@ final class API
|
||||
* @return object|array
|
||||
* @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);
|
||||
|
||||
@ -114,19 +135,37 @@ final class API
|
||||
try {
|
||||
$response = curl_exec($request);
|
||||
|
||||
switch($x=curl_getinfo($request,CURLINFO_HTTP_CODE)) {
|
||||
switch ($x=curl_getinfo($request,CURLINFO_HTTP_CODE)) {
|
||||
case 0:
|
||||
switch (curl_errno($request)) {
|
||||
// DNS Resolving issue
|
||||
case 6:
|
||||
throw new ConnectionIssueException(sprintf('%s:%s',self::LOGKEY,curl_error($request)));
|
||||
|
||||
default:
|
||||
dump(['getinfo' => curl_getinfo($request),'curlerror' => curl_error($request),'errno' => curl_errno($request)]);
|
||||
abort(500,'Error 0');
|
||||
}
|
||||
|
||||
case 400:
|
||||
case 401:
|
||||
case 403:
|
||||
case 404:
|
||||
dump([$xx=curl_getinfo($request),'response'=>$response]);
|
||||
dump([$xx=curl_getinfo($request),'response' => $response]);
|
||||
|
||||
throw new \Exception(sprintf('CURL exec returned %d: %s (%s)',$x,curl_error($request),serialize($xx)));
|
||||
}
|
||||
|
||||
curl_close($request);
|
||||
|
||||
if (! $response)
|
||||
throw new \Exception(sprintf('%s:Request to [%s] returned no data?',self::LOGKEY,$url),['code'=>$x]);
|
||||
|
||||
return json_decode(self::CURLOPT_HEADER ? substr($response,curl_getinfo($request,CURLINFO_HEADER_SIZE)) : $response);
|
||||
|
||||
} catch (ConnectException|ConnectionIssueException $e) {
|
||||
throw new ConnectionIssueException($e->getMessage());
|
||||
|
||||
} catch (\Exception $e) {
|
||||
dump(['error'=>$e->getMessage()]);
|
||||
Log::error(sprintf('%s:Got an error while posting to [%s] (%s)',static::LOGKEY,$url,$e->getMessage()),['m'=>__METHOD__]);
|
||||
@ -136,9 +175,57 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return ListList
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getClasses(array $parameters=[]): ListList
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a list of classes',static::LOGKEY));
|
||||
$key = 'Class';
|
||||
$parameters['query'] = 'select * from Class';
|
||||
|
||||
return new ListList($this->execute('query',$parameters),$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific customer record
|
||||
*
|
||||
@ -157,8 +244,6 @@ final class API
|
||||
/**
|
||||
* Get a list of our clients
|
||||
*
|
||||
* select * from Account where Metadata.CreateTime > '2014-12-31'
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return ListList
|
||||
* @throws \Exception
|
||||
@ -166,16 +251,138 @@ final class API
|
||||
public function getCustomers(array $parameters=[]): ListList
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a list of customers',static::LOGKEY));
|
||||
$key = 'customers';
|
||||
$key = 'Customer';
|
||||
$parameters['query'] = 'select * from Customer';
|
||||
|
||||
return new ListList($this->execute('query',$parameters),$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an invoice by its Document Number
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $parameters
|
||||
* @return Invoice
|
||||
* @throws InvalidQueryResultException
|
||||
*/
|
||||
public function getInvoiceQuery(string $id,array $parameters=[]): Invoice
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a specific invoice [%s]',static::LOGKEY,$id));
|
||||
|
||||
$table = 'Invoice';
|
||||
$parameters['query'] = sprintf("select * from %s where DocNumber='%s'",$table,$id);
|
||||
$result = object_get($this->execute('query',$parameters,$table),$table);
|
||||
|
||||
return new Invoice(array_pop($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of our invoices
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return ListList
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getInvoices(array $parameters=[]): ListList
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a list of invoices',static::LOGKEY));
|
||||
$key = 'Invoice';
|
||||
$parameters['query'] = 'select * from Invoice';
|
||||
|
||||
return new ListList($this->execute('query',$parameters),$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of our items
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return ListList
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getItems(array $parameters=[]): ListList
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a list of items',static::LOGKEY));
|
||||
$key = 'Item';
|
||||
$parameters['query'] = 'select * from Item';
|
||||
|
||||
return new ListList($this->execute('query',$parameters,$key),$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific payment record
|
||||
*
|
||||
* @param int $id
|
||||
* @param array $parameters
|
||||
* @return Payment
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getPayment(int $id,array $parameters=[]): Payment
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a specific payment [%d]',static::LOGKEY,$id));
|
||||
|
||||
$x = $this->execute('payment/'.$id,$parameters);
|
||||
|
||||
if (! $x->Payment)
|
||||
throw new InvalidQueryResultException(sprintf('%s:Query response malformed',self::LOGKEY));
|
||||
|
||||
return new Payment((array)$x->Payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of our payments
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return ListList
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getPayments(array $parameters=[]): ListList
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a list of payments',static::LOGKEY));
|
||||
$key = 'Payment';
|
||||
$parameters['query'] = 'select * from Payment';
|
||||
|
||||
return new ListList($this->execute('query',$parameters),$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return ListList
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getTaxCodes(array $parameters=[]): ListList
|
||||
{
|
||||
Log::debug(sprintf('%s:Get a list of taxes',static::LOGKEY));
|
||||
$key = 'TaxCode';
|
||||
$parameters['query'] = 'select * from TaxCode';
|
||||
|
||||
return new ListList($this->execute('query',$parameters,$key),$key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the API call
|
||||
*
|
||||
* @param $url
|
||||
* @param string $url
|
||||
* @param array $parameters
|
||||
* @param array $headers
|
||||
* @return \CurlHandle
|
||||
@ -211,7 +418,23 @@ final class API
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a customer
|
||||
* Create/Update an invoice
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return Invoice
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function updateInvoice(array $parameters=[]): Invoice
|
||||
{
|
||||
Log::debug(sprintf('%s:Update invoice',static::LOGKEY),['params'=>$parameters]);
|
||||
|
||||
$result = $this->execute('invoice',array_merge($parameters,['method'=>'POST']));
|
||||
|
||||
return new Invoice($result->Invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/Update a customer
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return Customer
|
||||
@ -221,6 +444,8 @@ final class API
|
||||
{
|
||||
Log::debug(sprintf('%s:Update customer',static::LOGKEY),['params'=>$parameters]);
|
||||
|
||||
return new Customer($this->execute('customer',array_merge($parameters,['method'=>'POST'])));
|
||||
$result = $this->execute('customer',array_merge($parameters,['method'=>'POST']));
|
||||
|
||||
return new Customer($result->Customer);
|
||||
}
|
||||
}
|
56
src/Commands/AccountGet.php
Normal file
56
src/Commands/AccountGet.php
Normal 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;
|
||||
}
|
||||
}
|
56
src/Commands/InvoiceGet.php
Normal file
56
src/Commands/InvoiceGet.php
Normal 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;
|
||||
}
|
||||
}
|
61
src/Commands/PaymentGet.php
Normal file
61
src/Commands/PaymentGet.php
Normal 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;
|
||||
}
|
||||
}
|
57
src/Commands/TaxCodeGet.php
Normal file
57
src/Commands/TaxCodeGet.php
Normal 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;
|
||||
}
|
||||
}
|
54
src/Commands/TokenRefresh.php
Normal file
54
src/Commands/TokenRefresh.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* Refresh the Intuit tokens
|
||||
*/
|
||||
class TokenRefresh extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:token:refresh'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Refresh an access token';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws \Intuit\Exceptions\NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$to = $this->providerToken($this->argument('user'));
|
||||
|
||||
$old = $to->refresh_token;
|
||||
|
||||
$x = $to->refreshToken();
|
||||
|
||||
dump([
|
||||
'access'=>$to->access_token,
|
||||
'old'=>$old,
|
||||
'refresh'=>$to->refresh_token,
|
||||
'expires'=>(string)$to->refresh_token_expires_at,
|
||||
'x'=>$x,
|
||||
]);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
75
src/Controllers/Webhook.php
Normal file
75
src/Controllers/Webhook.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Controllers;
|
||||
|
||||
use App\Events\ProviderPaymentCreated;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Intuit\Response\Webhook as Payload;
|
||||
|
||||
class Webhook extends BaseController
|
||||
{
|
||||
use DispatchesJobs;
|
||||
|
||||
private const name = 'intuit';
|
||||
|
||||
public function webhook(Request $request)
|
||||
{
|
||||
$signature = $request->header('Intuit-Signature');
|
||||
// Load the secret, you also can load it from env(YOUR_OWN_SLACK_SECRET)
|
||||
$secret = config(sprintf('services.provider.%s.verifytoken',self::name));
|
||||
|
||||
Log::channel('webhook')->debug('Payload: '.$request->getContent());
|
||||
Log::channel('webhook')->debug('Signature: '.$signature);
|
||||
|
||||
$payloadHash = hash_hmac('sha256',$request->getContent(),$secret);
|
||||
$singatureHash = bin2hex(base64_decode($signature));
|
||||
|
||||
if ($payloadHash == $singatureHash) {
|
||||
Log::channel('webhook')->debug('Signature OK');
|
||||
} else {
|
||||
Log::channel('webhook')->alert('Signature NOT ok.');
|
||||
}
|
||||
|
||||
$payload = new Payload(json_decode($request->getContent(),TRUE));
|
||||
|
||||
foreach ($payload->types() as $type) {
|
||||
|
||||
switch ($type) {
|
||||
case 'eventNotifications':
|
||||
|
||||
foreach ($payload->event($type) as $dataObject) {
|
||||
Log::info('Event for realm: '.$dataObject['realmId'],['data'=>$dataObject]);
|
||||
|
||||
foreach ($dataObject['dataChangeEvent'] as $object => $data) {
|
||||
switch ($object) {
|
||||
case 'entities':
|
||||
foreach ($data as $eventData) {
|
||||
switch ($x=$eventData['name']) {
|
||||
case 'Payment':
|
||||
Log::alert(sprintf('We got a payment event [%s:%s]',$object,$x),['data'=>$eventData]);
|
||||
event(new ProviderPaymentCreated('intuit',$eventData));
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::alert(sprintf('We dont know how to handle [%s:%s] yet',$object,$x),['data'=>$eventData]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::error(sprintf('Unknown object: %s in %s',$object,$type),['data'=>$data]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::error('Unknown webhook payload type: '.$type,['data'=>$data]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
src/Exceptions/ConnectionIssueException.php
Normal file
9
src/Exceptions/ConnectionIssueException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ConnectionIssueException extends Exception
|
||||
{
|
||||
}
|
9
src/Exceptions/InvalidQueryResultException.php
Normal file
9
src/Exceptions/InvalidQueryResultException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidQueryResultException extends Exception
|
||||
{
|
||||
}
|
9
src/Exceptions/NotFoundException.php
Normal file
9
src/Exceptions/NotFoundException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NotFoundException extends Exception
|
||||
{
|
||||
}
|
9
src/Exceptions/NotTokenException.php
Normal file
9
src/Exceptions/NotTokenException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NotTokenException extends Exception
|
||||
{
|
||||
}
|
@ -9,69 +9,73 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use Intuit\Models\{Customer,ProviderToken};
|
||||
use App\Models\Account as AppAccount;
|
||||
|
||||
class AccountingCustomerUpdate implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JAS';
|
||||
|
||||
private Customer $customer;
|
||||
private Customer $o;
|
||||
private ProviderToken $to;
|
||||
private bool $forceprod;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProviderToken $to,Customer $customer,bool $forcprod=FALSE)
|
||||
{
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProviderToken $to,Customer $item)
|
||||
{
|
||||
$this->onQueue('intuit');
|
||||
|
||||
$this->customer = $customer;
|
||||
$this->o = $item;
|
||||
$this->to = $to->withoutRelations();
|
||||
$this->forceprod = $forcprod;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set('site',$this->to->site);
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$api = $this->to->API();
|
||||
|
||||
// Get the original account, so we can get the provider sync details
|
||||
$o = $this->to->provider->accounts->where('id',$x=(int)substr($this->o->ResaleNum,3));
|
||||
$o = ($o->count() === 1) ? $o->pop() : AppAccount::findOrFail($x);
|
||||
|
||||
$api = $this->to->provider->API($this->to,$this->forceprod);
|
||||
$updated = $api->updateCustomer(array_merge(
|
||||
$this->customer->getDirty(),
|
||||
[
|
||||
'Id'=>$this->customer->id,
|
||||
'SyncToken'=>$this->customer->synctoken,
|
||||
]));
|
||||
$this->o->getDirty(),
|
||||
$o->providers->count()
|
||||
?
|
||||
[
|
||||
'Id'=>$o->pivot->ref,
|
||||
'SyncToken'=>$o->pivot->synctoken,
|
||||
]
|
||||
:
|
||||
[]
|
||||
));
|
||||
|
||||
if (($x=$this->to->provider->accounts->where('pivot.ref',$updated->id))->count() === 1) {
|
||||
$ao = $x->pop();
|
||||
|
||||
$ao->providers()->syncWithoutDetaching([
|
||||
if ($updated instanceof \Intuit\Response\Customer) {
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$this->to->provider->id => [
|
||||
'ref' => $updated->id,
|
||||
'synctoken' => $updated->synctoken,
|
||||
'created_at'=>Carbon::create($updated->created_at),
|
||||
'updated_at'=>Carbon::create($updated->updated_at),
|
||||
'site_id'=>$ao->site_id, // @todo See if we can have this handled automatically
|
||||
'site_id'=>$o->site_id, // @todo See if we can have this handled automatically
|
||||
],
|
||||
]);
|
||||
|
||||
Log::info(sprintf('%s:Updated account [%s] (%s:%s), synctoken now [%s]',self::LOGKEY,$ao->sid,$updated->id,$updated->DisplayName,$updated->synctoken));
|
||||
Log::info(sprintf('%s:Updated account [%s:%s] (%s:%s), synctoken now [%s]',self::LOGKEY,$this->to->provider->name,$o->sid,$updated->id,$updated->DisplayName,$updated->synctoken));
|
||||
|
||||
} else {
|
||||
Log::error(sprintf('%s:Unable to update account refer for [%s:%s]',self::LOGKEY,$updated->id,$updated->DisplayName));
|
||||
Log::error(sprintf('%s:Unable to update account with provider [%s] for [%s:%s]',self::LOGKEY,$this->to->provider->name,$updated->id,$updated->DisplayName),['updated'=>get_class($updated)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
src/Jobs/AccountingInvoiceUpdate.php
Normal file
81
src/Jobs/AccountingInvoiceUpdate.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use Intuit\Models\{Invoice,ProviderToken};
|
||||
use App\Models\Invoice as AppInvoice;
|
||||
|
||||
class AccountingInvoiceUpdate implements ShouldQueue
|
||||
{
|
||||
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JIU';
|
||||
|
||||
private Invoice $o;
|
||||
private ProviderToken $to;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProviderToken $to,Invoice $item)
|
||||
{
|
||||
$this->onQueue('intuit');
|
||||
|
||||
$this->o = $item;
|
||||
$this->to = $to->withoutRelations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$api = $this->to->API();
|
||||
|
||||
// Get the original invoice, so we can get the provider sync details
|
||||
$o = $this->to->provider->invoices->where('id',$this->o->DocNumber);
|
||||
$o = ($o->count() === 1) ? $o->pop() : AppInvoice::findOrFail($this->o->DocNumber);
|
||||
|
||||
$updated = $api->updateInvoice(array_merge(
|
||||
$this->o->getDirty(),
|
||||
$o->providers->count()
|
||||
?
|
||||
[
|
||||
'Id'=>$o->pivot->ref,
|
||||
'SyncToken'=>$o->pivot->synctoken,
|
||||
]
|
||||
:
|
||||
[]
|
||||
));
|
||||
|
||||
if ($updated instanceof \Intuit\Response\Invoice) {
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$this->to->provider->id => [
|
||||
'ref' => $updated->id,
|
||||
'synctoken' => $updated->synctoken,
|
||||
'created_at'=>Carbon::create($updated->created_at),
|
||||
'updated_at'=>Carbon::create($updated->updated_at),
|
||||
'site_id'=>$o->site_id, // @todo See if we can have this handled automatically
|
||||
],
|
||||
]);
|
||||
|
||||
Log::info(sprintf('%s:Updated invoice [%s:%s] (%s:%s), synctoken now [%s]',self::LOGKEY,$this->to->provider->name,$o->sid,$updated->id,$updated->DocNumber,$updated->synctoken));
|
||||
|
||||
} else {
|
||||
Log::error(sprintf('%s:Unable to update invoice with provider [%s] for [%s:%s]',self::LOGKEY,$this->to->provider->name,$updated->id,$updated->DisplayName),['updated'=>get_class($updated)]);
|
||||
}
|
||||
}
|
||||
}
|
35
src/Models/Category.php
Normal file
35
src/Models/Category.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
|
||||
/*
|
||||
|
||||
+"time": "2022-08-13T21:15:37.254-07:00"
|
||||
*/
|
||||
|
||||
final class Category extends Model
|
||||
{
|
||||
use CompareAttributes;
|
||||
|
||||
public function __get($key) {
|
||||
$keymap = [
|
||||
'id' => 'Id',
|
||||
'synctoken' => 'SyncToken',
|
||||
];
|
||||
|
||||
switch ($key) {
|
||||
case 'created_at':
|
||||
return object_get($this->getAttribute('MetaData'),'CreateTime');
|
||||
case 'updated_at':
|
||||
return object_get($this->getAttribute('MetaData'),'LastUpdatedTime');
|
||||
|
||||
default:
|
||||
return parent::__get(Arr::get($keymap,$key,$key));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,10 @@
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
|
||||
/*
|
||||
+"Customer": {#1760
|
||||
+"Taxable": false
|
||||
@ -54,11 +55,11 @@ final class Customer extends Model
|
||||
public function __get($key) {
|
||||
$keymap = [
|
||||
'id' => 'Id',
|
||||
'synctoken' => 'SyncToken',
|
||||
'active' => 'Active',
|
||||
'companyname' => 'CompanyName',
|
||||
'fullname' => 'FullyQualifiedName',
|
||||
'ref' => 'ResaleNum',
|
||||
'synctoken' => 'SyncToken',
|
||||
];
|
||||
|
||||
switch ($key) {
|
||||
@ -66,6 +67,8 @@ final class Customer extends Model
|
||||
return object_get($this->getAttribute('MetaData'),'CreateTime');
|
||||
case 'updated_at':
|
||||
return object_get($this->getAttribute('MetaData'),'LastUpdatedTime');
|
||||
case 'email':
|
||||
return object_get($this->getAttribute('PrimaryEmailAddr'),'Address');
|
||||
|
||||
default:
|
||||
return parent::__get(Arr::get($keymap,$key,$key));
|
||||
|
144
src/Models/Invoice.php
Normal file
144
src/Models/Invoice.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
|
||||
/*
|
||||
{#5766
|
||||
+"AllowIPNPayment": false
|
||||
+"AllowOnlinePayment": false
|
||||
+"AllowOnlineCreditCardPayment": false
|
||||
+"AllowOnlineACHPayment": false
|
||||
+"domain": "QBO"
|
||||
+"sparse": false
|
||||
+"Id": "192"
|
||||
+"SyncToken": "0"
|
||||
+"MetaData": {#5765
|
||||
+"CreateTime": "2018-06-09T07:41:49-07:00"
|
||||
+"LastUpdatedTime": "2018-06-09T07:41:49-07:00"
|
||||
}
|
||||
+"CustomField": array:1 [
|
||||
0 => {#5764
|
||||
+"DefinitionId": "1"
|
||||
+"Name": "Event Rep"
|
||||
+"Type": "StringType"
|
||||
}
|
||||
]
|
||||
+"DocNumber": "1022"
|
||||
+"TxnDate": "2018-06-10"
|
||||
+"CurrencyRef": {#5763
|
||||
+"value": "AUD"
|
||||
+"name": "Australian Dollar"
|
||||
}
|
||||
+"ExchangeRate": 1
|
||||
+"LinkedTxn": []
|
||||
+"Line": array:2 [
|
||||
0 => {#5762
|
||||
+"Id": "1"
|
||||
+"LineNum": 1
|
||||
+"Description": "Holiday party - gold level"
|
||||
+"Amount": 6000.0
|
||||
+"DetailType": "SalesItemLineDetail"
|
||||
+"SalesItemLineDetail": {#5761
|
||||
+"TaxInclusiveAmt": 6600.0
|
||||
+"ItemRef": {#5760
|
||||
+"value": "7"
|
||||
+"name": "Holiday party:Gold party"
|
||||
}
|
||||
+"UnitPrice": 2000
|
||||
+"Qty": 3
|
||||
+"ItemAccountRef": {#5759
|
||||
+"value": "1"
|
||||
+"name": "Services"
|
||||
}
|
||||
+"TaxCodeRef": {#5758
|
||||
+"value": "10"
|
||||
}
|
||||
}
|
||||
}
|
||||
1 => {#5757
|
||||
+"Amount": 6000.0
|
||||
+"DetailType": "SubTotalLineDetail"
|
||||
+"SubTotalLineDetail": {#5756}
|
||||
}
|
||||
]
|
||||
+"TxnTaxDetail": {#5755
|
||||
+"TotalTax": 600.0
|
||||
+"TaxLine": array:1 [
|
||||
0 => {#5754
|
||||
+"Amount": 600.0
|
||||
+"DetailType": "TaxLineDetail"
|
||||
+"TaxLineDetail": {#5753
|
||||
+"TaxRateRef": {#5752
|
||||
+"value": "20"
|
||||
}
|
||||
+"PercentBased": true
|
||||
+"TaxPercent": 10
|
||||
+"NetAmountTaxable": 6000.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+"RecurDataRef": {#5751
|
||||
+"value": "11"
|
||||
}
|
||||
+"CustomerRef": {#5750
|
||||
+"value": "17"
|
||||
+"name": "Jordan Burgess"
|
||||
}
|
||||
+"CustomerMemo": {#5749
|
||||
+"value": "Thanks for your business! We appreciate referrals!"
|
||||
}
|
||||
+"BillAddr": {#5748
|
||||
+"Id": "15"
|
||||
+"Line1": "1 Success Way"
|
||||
+"City": "Sydney"
|
||||
+"CountrySubDivisionCode": "NSW"
|
||||
+"PostalCode": "2000"
|
||||
+"Lat": "-33.871226"
|
||||
+"Long": "150.897656"
|
||||
}
|
||||
+"FreeFormAddress": false
|
||||
+"SalesTermRef": {#5747
|
||||
+"value": "3"
|
||||
}
|
||||
+"DueDate": "2018-07-10"
|
||||
+"GlobalTaxCalculation": "TaxInclusive"
|
||||
+"TotalAmt": 6600.0
|
||||
+"HomeTotalAmt": 6600.0
|
||||
+"PrintStatus": "NotSet"
|
||||
+"EmailStatus": "NotSet"
|
||||
+"Balance": 6600.0
|
||||
+"HomeBalance": 6600.0
|
||||
}
|
||||
+"time": "2022-08-13T21:15:37.254-07:00"
|
||||
*/
|
||||
|
||||
final class Invoice extends Model
|
||||
{
|
||||
use CompareAttributes;
|
||||
|
||||
public function __get($key) {
|
||||
$keymap = [
|
||||
'id' => 'Id',
|
||||
'synctoken' => 'SyncToken',
|
||||
'invoice_num' => 'DocNumber',
|
||||
'invoice_date' => 'TxnDate',
|
||||
'due_date' => 'DueDate',
|
||||
];
|
||||
|
||||
switch ($key) {
|
||||
case 'created_at':
|
||||
return object_get($this->getAttribute('MetaData'),'CreateTime');
|
||||
case 'updated_at':
|
||||
return object_get($this->getAttribute('MetaData'),'LastUpdatedTime');
|
||||
|
||||
default:
|
||||
return parent::__get(Arr::get($keymap,$key,$key));
|
||||
}
|
||||
}
|
||||
}
|
80
src/Models/Item.php
Normal file
80
src/Models/Item.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
|
||||
/*
|
||||
{#1927
|
||||
+"Name": "Silver retreat"
|
||||
+"Description": "Retreat - silver level"
|
||||
+"Active": true
|
||||
+"SubItem": true
|
||||
+"ParentRef": {#1928
|
||||
+"value": "25"
|
||||
+"name": "Retreat"
|
||||
}
|
||||
+"Level": 1
|
||||
+"FullyQualifiedName": "Retreat:Silver retreat"
|
||||
+"Taxable": false
|
||||
+"SalesTaxIncluded": false
|
||||
+"UnitPrice": 1000
|
||||
+"Type": "Service"
|
||||
+"IncomeAccountRef": {#1929
|
||||
+"value": "1"
|
||||
+"name": "Services"
|
||||
}
|
||||
+"PurchaseTaxIncluded": false
|
||||
+"PurchaseCost": 0
|
||||
+"ExpenseAccountRef": {#1930
|
||||
+"value": "89"
|
||||
+"name": "Purchases"
|
||||
}
|
||||
+"TrackQtyOnHand": false
|
||||
+"SalesTaxCodeRef": {#1931
|
||||
+"value": "10"
|
||||
+"name": "GST"
|
||||
}
|
||||
+"PurchaseTaxCodeRef": {#1932
|
||||
+"value": "2"
|
||||
+"name": "GST on non-capital"
|
||||
}
|
||||
+"domain": "QBO"
|
||||
+"sparse": false
|
||||
+"Id": "15"
|
||||
+"SyncToken": "1"
|
||||
+"MetaData": {#1933
|
||||
+"CreateTime": "2018-02-21T20:30:11-08:00"
|
||||
+"LastUpdatedTime": "2018-06-15T21:19:52-07:00"
|
||||
}
|
||||
}
|
||||
+"time": "2022-08-13T21:15:37.254-07:00"
|
||||
*/
|
||||
|
||||
final class Item extends Model
|
||||
{
|
||||
use CompareAttributes;
|
||||
|
||||
public function __get($key) {
|
||||
$keymap = [
|
||||
'id' => 'Id',
|
||||
'synctoken' => 'SyncToken',
|
||||
];
|
||||
|
||||
switch ($key) {
|
||||
case 'created_at':
|
||||
return object_get($this->getAttribute('MetaData'),'CreateTime');
|
||||
case 'updated_at':
|
||||
return object_get($this->getAttribute('MetaData'),'LastUpdatedTime');
|
||||
|
||||
case 'pid':
|
||||
return (($x=object_get($this->getAttribute('ParentRef'),'name')) ? $x.':' : '').$this->Name;
|
||||
|
||||
default:
|
||||
return parent::__get(Arr::get($keymap,$key,$key));
|
||||
}
|
||||
}
|
||||
}
|
183
src/Models/Payment.php
Normal file
183
src/Models/Payment.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
|
||||
/*
|
||||
{#5731
|
||||
+"QueryResponse": {#5730
|
||||
+"Payment": array:1 [
|
||||
0 => {#5729
|
||||
+"CustomerRef": {#5728
|
||||
+"value": "70"
|
||||
+"name": "Customer Name"
|
||||
}
|
||||
+"DepositToAccountRef": {#5727
|
||||
+"value": "135"
|
||||
}
|
||||
+"TotalAmt": 133.0
|
||||
+"UnappliedAmt": 0
|
||||
+"ProcessPayment": false
|
||||
+"domain": "QBO"
|
||||
+"sparse": false
|
||||
+"Id": "208"
|
||||
+"SyncToken": "0"
|
||||
+"MetaData": {#5726
|
||||
+"CreateTime": "2023-05-12T22:19:55-07:00"
|
||||
+"LastUpdatedTime": "2023-05-12T22:19:55-07:00"
|
||||
}
|
||||
+"TxnDate": "2023-05-13"
|
||||
+"CurrencyRef": {#5725
|
||||
+"value": "AUD"
|
||||
+"name": "Australian Dollar"
|
||||
}
|
||||
+"Line": array:2 [
|
||||
0 => {#5724
|
||||
+"Amount": 1.0
|
||||
+"LinkedTxn": array:1 [
|
||||
0 => {#5723
|
||||
+"TxnId": "202"
|
||||
+"TxnType": "Invoice"
|
||||
}
|
||||
]
|
||||
+"LineEx": {#5722
|
||||
+"any": array:3 [
|
||||
0 => {#5721
|
||||
+"name": "{http://schema.intuit.com/finance/v3}NameValue"
|
||||
+"declaredType": "com.intuit.schema.finance.v3.NameValue"
|
||||
+"scope": "javax.xml.bind.JAXBElement$GlobalScope"
|
||||
+"value": {#5720
|
||||
+"Name": "txnId"
|
||||
+"Value": "202"
|
||||
}
|
||||
+"nil": false
|
||||
+"globalScope": true
|
||||
+"typeSubstituted": false
|
||||
}
|
||||
1 => {#5719
|
||||
+"name": "{http://schema.intuit.com/finance/v3}NameValue"
|
||||
+"declaredType": "com.intuit.schema.finance.v3.NameValue"
|
||||
+"scope": "javax.xml.bind.JAXBElement$GlobalScope"
|
||||
+"value": {#5718
|
||||
+"Name": "txnOpenBalance"
|
||||
+"Value": "132.00"
|
||||
}
|
||||
+"nil": false
|
||||
+"globalScope": true
|
||||
+"typeSubstituted": false
|
||||
}
|
||||
2 => {#5717
|
||||
+"name": "{http://schema.intuit.com/finance/v3}NameValue"
|
||||
+"declaredType": "com.intuit.schema.finance.v3.NameValue"
|
||||
+"scope": "javax.xml.bind.JAXBElement$GlobalScope"
|
||||
+"value": {#5716
|
||||
+"Name": "txnReferenceNumber"
|
||||
+"Value": "006825.4"
|
||||
}
|
||||
+"nil": false
|
||||
+"globalScope": true
|
||||
+"typeSubstituted": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
1 => {#5715
|
||||
+"Amount": 132.0
|
||||
+"LinkedTxn": array:1 [
|
||||
0 => {#5714
|
||||
+"TxnId": "206"
|
||||
+"TxnType": "Invoice"
|
||||
}
|
||||
]
|
||||
+"LineEx": {#5713
|
||||
+"any": array:3 [
|
||||
0 => {#5712
|
||||
+"name": "{http://schema.intuit.com/finance/v3}NameValue"
|
||||
+"declaredType": "com.intuit.schema.finance.v3.NameValue"
|
||||
+"scope": "javax.xml.bind.JAXBElement$GlobalScope"
|
||||
+"value": {#5711
|
||||
+"Name": "txnId"
|
||||
+"Value": "206"
|
||||
}
|
||||
+"nil": false
|
||||
+"globalScope": true
|
||||
+"typeSubstituted": false
|
||||
}
|
||||
1 => {#5710
|
||||
+"name": "{http://schema.intuit.com/finance/v3}NameValue"
|
||||
+"declaredType": "com.intuit.schema.finance.v3.NameValue"
|
||||
+"scope": "javax.xml.bind.JAXBElement$GlobalScope"
|
||||
+"value": {#5709
|
||||
+"Name": "txnOpenBalance"
|
||||
+"Value": "132.00"
|
||||
}
|
||||
+"nil": false
|
||||
+"globalScope": true
|
||||
+"typeSubstituted": false
|
||||
}
|
||||
2 => {#5708
|
||||
+"name": "{http://schema.intuit.com/finance/v3}NameValue"
|
||||
+"declaredType": "com.intuit.schema.finance.v3.NameValue"
|
||||
+"scope": "javax.xml.bind.JAXBElement$GlobalScope"
|
||||
+"value": {#5707
|
||||
+"Name": "txnReferenceNumber"
|
||||
+"Value": "006813"
|
||||
}
|
||||
+"nil": false
|
||||
+"globalScope": true
|
||||
+"typeSubstituted": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
+"startPosition": 1
|
||||
+"maxResults": 1
|
||||
}
|
||||
+"time": "2023-05-12T22:20:40.937-07:00"
|
||||
}
|
||||
*/
|
||||
|
||||
final class Payment extends Model
|
||||
{
|
||||
use CompareAttributes;
|
||||
|
||||
public function __get($key) {
|
||||
$keymap = [
|
||||
'id' => 'Id',
|
||||
'synctoken' => 'SyncToken',
|
||||
'date_paid' => 'TxnDate',
|
||||
'total_amt' => 'TotalAmt',
|
||||
'unapplied' => 'UnappliedAmt',
|
||||
];
|
||||
|
||||
switch ($key) {
|
||||
case 'created_at':
|
||||
return object_get($this->getAttribute('MetaData'),'CreateTime');
|
||||
case 'updated_at':
|
||||
return object_get($this->getAttribute('MetaData'),'LastUpdatedTime');
|
||||
|
||||
case 'account_ref':
|
||||
return object_get($this->getAttribute('CustomerRef'),'value');
|
||||
|
||||
default:
|
||||
return parent::__get(Arr::get($keymap,$key,$key));
|
||||
}
|
||||
}
|
||||
|
||||
public function lines(): Collection
|
||||
{
|
||||
$result = collect($this->getAttribute('Line'))->transform(function($item) {
|
||||
return $item->LinkedTxn[0]->TxnType === 'Invoice' ? [ $item->LinkedTxn[0]->TxnId => $item->Amount] : [];
|
||||
});
|
||||
|
||||
return collect(array_replace(...$result));
|
||||
}
|
||||
}
|
@ -3,18 +3,21 @@
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
class ProviderToken extends Model
|
||||
{
|
||||
protected $dates = [
|
||||
'access_token_expires_at',
|
||||
'refresh_token_expires_at',
|
||||
private const LOGKEY = 'IPT';
|
||||
|
||||
protected $casts = [
|
||||
'access_token_expires_at' => 'datetime:Y-m-d H:i:s',
|
||||
'refresh_token_expires_at' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getAccessTokenAttribute($value): ?string
|
||||
public function getAccessTokenAttribute(string $value): ?string
|
||||
{
|
||||
if (! $this->hasAccessTokenExpired())
|
||||
return $value;
|
||||
@ -29,11 +32,16 @@ class ProviderToken extends Model
|
||||
|
||||
public function hasAccessTokenExpired(): bool
|
||||
{
|
||||
return $this->access_token_expires_at->isPast();
|
||||
return $this
|
||||
->access_token_expires_at
|
||||
->isPast();
|
||||
}
|
||||
|
||||
public function refreshToken(): bool
|
||||
{
|
||||
return Socialite::with($this->provider->name)->refreshtoken($this);
|
||||
Log::debug(sprintf('%s:= Refreshing token for [%s]',self::LOGKEY,$this->provider->name));
|
||||
|
||||
return Socialite::with($this->provider->name)
|
||||
->refreshToken($this);
|
||||
}
|
||||
}
|
66
src/Models/Taxcode.php
Normal file
66
src/Models/Taxcode.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Models;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Traits\CompareAttributes;
|
||||
|
||||
/*
|
||||
{#2052
|
||||
+"Name": "GST"
|
||||
+"Description": "GST"
|
||||
+"Active": true
|
||||
+"Hidden": false
|
||||
+"Taxable": true
|
||||
+"TaxGroup": true
|
||||
+"SalesTaxRateList": {#2053
|
||||
+"TaxRateDetail": array:1 [
|
||||
0 => {#2054
|
||||
+"TaxRateRef": {#2055
|
||||
+"value": "23"
|
||||
+"name": "GST (sales)"
|
||||
}
|
||||
+"TaxTypeApplicable": "TaxOnAmount"
|
||||
+"TaxOrder": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
+"PurchaseTaxRateList": {#2056
|
||||
+"TaxRateDetail": []
|
||||
}
|
||||
+"TaxCodeConfigType": "SYSTEM_GENERATED"
|
||||
+"domain": "QBO"
|
||||
+"sparse": false
|
||||
+"Id": "14"
|
||||
+"SyncToken": "0"
|
||||
+"MetaData": {#2057
|
||||
+"CreateTime": "2023-05-10T01:05:41-07:00"
|
||||
+"LastUpdatedTime": "2023-05-10T01:05:41-07:00"
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
final class Taxcode extends Model
|
||||
{
|
||||
use CompareAttributes;
|
||||
|
||||
public function __get($key) {
|
||||
$keymap = [
|
||||
'id' => 'Id',
|
||||
'synctoken' => 'SyncToken',
|
||||
'name' => 'Name',
|
||||
];
|
||||
|
||||
switch ($key) {
|
||||
case 'created_at':
|
||||
return object_get($this->getAttribute('MetaData'),'CreateTime');
|
||||
case 'updated_at':
|
||||
return object_get($this->getAttribute('MetaData'),'LastUpdatedTime');
|
||||
|
||||
default:
|
||||
return parent::__get(Arr::get($keymap,$key,$key));
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace Intuit\Providers;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Intuit\Commands\{AccountGet,InvoiceGet,PaymentGet,TaxCodeGet,TokenRefresh};
|
||||
|
||||
/**
|
||||
* Class IntuitServiceProvider.
|
||||
@ -20,6 +21,14 @@ class IntuitServiceProvider extends ServiceProvider
|
||||
public function boot(Router $router)
|
||||
{
|
||||
$this->mergeConfigFrom($this->_path.'/config/intuit.php','intuit');
|
||||
|
||||
$this->commands([
|
||||
AccountGet::class,
|
||||
InvoiceGet::class,
|
||||
PaymentGet::class,
|
||||
TaxCodeGet::class,
|
||||
TokenRefresh::class,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,8 +38,7 @@ class IntuitServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if (! $this->_path) {
|
||||
if (! $this->_path)
|
||||
$this->_path = realpath(__DIR__.'/../../src');
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ use Carbon\Carbon;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laravel\Passport\Exceptions\InvalidAuthTokenException;
|
||||
use Laravel\Socialite\Two\InvalidStateException;
|
||||
use Laravel\Socialite\Two\ProviderInterface;
|
||||
@ -16,6 +17,8 @@ use App\Models\{ProviderOauth,ProviderToken};
|
||||
|
||||
class IntuitProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
private const LOGKEY = 'SIP';
|
||||
|
||||
private const hosts = [
|
||||
'authorise' => 'https://appcenter.intuit.com/connect/oauth2',
|
||||
'tokenendpoint' => 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer',
|
||||
@ -104,12 +107,16 @@ class IntuitProvider extends AbstractProvider implements ProviderInterface
|
||||
];
|
||||
}
|
||||
|
||||
public function refreshtoken(ProviderToken $to): bool
|
||||
public function refreshToken($to)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
RequestOptions::HEADERS => $this->getAuthorisationHeader($to->provider),
|
||||
RequestOptions::FORM_PARAMS => $this->getRefreshTokenFields($to->refresh_token),
|
||||
]);
|
||||
Log::debug(sprintf('%s:= Refreshing token for [%d]',self::LOGKEY,$to->id));
|
||||
|
||||
$response = $this
|
||||
->getHttpClient()
|
||||
->post($this->getTokenUrl(),[
|
||||
RequestOptions::HEADERS => $this->getAuthorisationHeader($to->provider),
|
||||
RequestOptions::FORM_PARAMS => $this->getRefreshTokenFields($to->refresh_token),
|
||||
]);
|
||||
|
||||
switch ($response->getStatusCode()) {
|
||||
case '200':
|
||||
@ -125,10 +132,11 @@ class IntuitProvider extends AbstractProvider implements ProviderInterface
|
||||
if (($x=Arr::get($body,'refresh_token')) !== $to->refresh_token) {
|
||||
$to->refresh_token = $x;
|
||||
$to->refresh_token_expires_at = Carbon::now()->addSeconds(Arr::get($body,'x_refresh_token_expires_in'));
|
||||
}
|
||||
$to->save();
|
||||
|
||||
return TRUE;
|
||||
Log::debug(sprintf('%s:= Refresh token updated.',self::LOGKEY));
|
||||
}
|
||||
|
||||
return $to->save();
|
||||
|
||||
default:
|
||||
throw new InvalidAuthTokenException(sprintf('Invalid response [%d] refreshing token for [%s] (%s)',$response->getStatusCode(),$to->user->email,$response->getBody()));
|
||||
|
@ -2,13 +2,10 @@
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Jenssegers\Model\Model;
|
||||
|
||||
use Intuit\Models\Customer;
|
||||
|
||||
/**
|
||||
* This parent class handles responses received from Intuit
|
||||
*
|
||||
@ -37,6 +34,10 @@ abstract class Base implements \JsonSerializable
|
||||
}
|
||||
}
|
||||
|
||||
public function __get($key) {
|
||||
return $this->_model->__get($key);
|
||||
}
|
||||
|
||||
/* ABSTRACT */
|
||||
|
||||
/**
|
||||
@ -54,8 +55,8 @@ abstract class Base implements \JsonSerializable
|
||||
* @param mixed $value
|
||||
* @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);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Intuit\Models\Customer as CustomerModel;
|
||||
|
||||
/**
|
||||
* This is a Customer Intuit Response to API calls
|
||||
*/
|
||||
@ -16,10 +18,6 @@ class Customer extends Base
|
||||
if (object_get($response,'time'))
|
||||
unset($response->time);
|
||||
|
||||
$this->_model = new \Intuit\Models\Customer((array)$response->Customer);
|
||||
}
|
||||
|
||||
public function __get($key) {
|
||||
return $this->_model->__get($key);
|
||||
$this->_model = new CustomerModel((array)$response);
|
||||
}
|
||||
}
|
23
src/Response/Invoice.php
Normal file
23
src/Response/Invoice.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Intuit\Models\Invoice as InvoiceModel;
|
||||
|
||||
/**
|
||||
* This is an Invoice Intuit Response to API calls
|
||||
*/
|
||||
class Invoice extends Base
|
||||
{
|
||||
protected const LOGKEY = 'RII';
|
||||
|
||||
public function __construct(object $response)
|
||||
{
|
||||
parent::__construct($response);
|
||||
|
||||
if (object_get($response,'time'))
|
||||
unset($response->time);
|
||||
|
||||
$this->_model = new InvoiceModel((array)$response);
|
||||
}
|
||||
}
|
@ -2,10 +2,12 @@
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Intuit\Models\Customer;
|
||||
|
||||
use Intuit\Models\{Category,Customer,Invoice,Item,Payment,Taxcode};
|
||||
|
||||
/**
|
||||
* This is a Generic Intuit Response to API calls that produces a list of objects
|
||||
@ -21,7 +23,12 @@ class ListList extends Base implements \Countable, \ArrayAccess, \Iterator
|
||||
|
||||
private ?int $counter = NULL;
|
||||
protected const TYPES = [
|
||||
'customers',
|
||||
'Class' => Category::class,
|
||||
'Customer' => Customer::class,
|
||||
'Invoice' => Invoice::class,
|
||||
'Item' => Item::class,
|
||||
'Payment' => Payment::class,
|
||||
'TaxCode' => Taxcode::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -35,7 +42,7 @@ class ListList extends Base implements \Countable, \ArrayAccess, \Iterator
|
||||
{
|
||||
parent::__construct($response);
|
||||
|
||||
if (! in_array($type,self::TYPES))
|
||||
if (! in_array($type,array_keys(self::TYPES)))
|
||||
throw new \Exception('Unknown data type: '.$type);
|
||||
|
||||
if (object_get($response,'time'))
|
||||
@ -44,7 +51,7 @@ class ListList extends Base implements \Countable, \ArrayAccess, \Iterator
|
||||
$this->_data = $this->data($response,$type);
|
||||
|
||||
// This is only for child classes
|
||||
if (get_class($this) == Base::class) {
|
||||
if (get_class($this) === Base::class) {
|
||||
Log::debug(sprintf('%s:Intuit RESPONSE Initialised [%s]',static::LOGKEY,get_class($this)),['m'=>__METHOD__]);
|
||||
|
||||
if (App::environment() == 'dev')
|
||||
@ -52,6 +59,22 @@ class ListList extends Base implements \Countable, \ArrayAccess, \Iterator
|
||||
}
|
||||
}
|
||||
|
||||
public function __call(string $name,array $args)
|
||||
{
|
||||
switch ($name) {
|
||||
case 'first':
|
||||
return $this->_data->{$name}();
|
||||
case 'pluck':
|
||||
if (count($args) !== 2)
|
||||
throw new \BadMethodCallException(sprintf('Pluck requires to arguments %s::%s()',get_class($this),$name));
|
||||
|
||||
return collect(array_replace(...$this->_data->map(function($item) use ($args) { return [$item->{$args[1]} => $item->{$args[0]}]; })));
|
||||
|
||||
default:
|
||||
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()',get_class($this),$name));
|
||||
}
|
||||
}
|
||||
|
||||
public function current(): mixed
|
||||
{
|
||||
return $this->_data[$this->counter];
|
||||
@ -121,16 +144,40 @@ class ListList extends Base implements \Countable, \ArrayAccess, \Iterator
|
||||
*/
|
||||
private function data(object $response,string $type): Collection
|
||||
{
|
||||
switch ($type) {
|
||||
case 'customers':
|
||||
$data = collect(Customer::hydrate($response->QueryResponse->Customer));
|
||||
$this->startPosition = $response->QueryResponse->startPosition;
|
||||
$this->maxResults = $response->QueryResponse->maxResults;
|
||||
$x = $response->{$type};
|
||||
switch (Arr::get(self::TYPES,$type)) {
|
||||
case Category::class:
|
||||
$data = collect(Category::hydrate($x));
|
||||
break;
|
||||
|
||||
default: throw new \Exception('Unknown object type: '.$this->_type);
|
||||
case Customer::class:
|
||||
$data = collect(Customer::hydrate($x));
|
||||
break;
|
||||
|
||||
case Invoice::class:
|
||||
$data = collect(Invoice::hydrate($x));
|
||||
break;
|
||||
|
||||
case Item::class:
|
||||
$data = collect(Item::hydrate($x));
|
||||
break;
|
||||
|
||||
case Payment::class:
|
||||
$data = collect(Payment::hydrate($x));
|
||||
break;
|
||||
|
||||
case Taxcode::class:
|
||||
$data = collect(Taxcode::hydrate($x));
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::error(sprintf('%s:Unknown object type: %s',self::LOGKEY,$type));
|
||||
throw new \Exception(sprintf('%s:Unknown object type: %s',self::LOGKEY,$type));
|
||||
}
|
||||
|
||||
$this->startPosition = $response->startPosition;
|
||||
$this->maxResults = $response->maxResults;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
23
src/Response/Payment.php
Normal file
23
src/Response/Payment.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Intuit\Models\Payment as PaymentModel;
|
||||
|
||||
/**
|
||||
* This is an Invoice Intuit Response to API calls
|
||||
*/
|
||||
class Payment extends Base
|
||||
{
|
||||
protected const LOGKEY = 'RIP';
|
||||
|
||||
public function __construct(object $response)
|
||||
{
|
||||
parent::__construct($response);
|
||||
|
||||
if (object_get($response,'time'))
|
||||
unset($response->time);
|
||||
|
||||
$this->_model = new PaymentModel((array)$response->Payment);
|
||||
}
|
||||
}
|
30
src/Response/Taxcode.php
Normal file
30
src/Response/Taxcode.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Intuit\Models\Taxcode as TaxcodeModel;
|
||||
|
||||
/**
|
||||
* This is an Invoice Intuit Response to API calls
|
||||
*/
|
||||
class Taxcode extends Base
|
||||
{
|
||||
protected const LOGKEY = 'RTI';
|
||||
|
||||
public function __construct(object $response)
|
||||
{
|
||||
parent::__construct($response);
|
||||
|
||||
if (object_get($response,'time'))
|
||||
unset($response->time);
|
||||
|
||||
$this->_model = new TaxcodeModel((array)$response);
|
||||
}
|
||||
|
||||
public function getTaxRateRef(): Collection
|
||||
{
|
||||
return collect($this->SalesTaxRateList->TaxRateDetail)
|
||||
->pluck('TaxRateRef.value');
|
||||
}
|
||||
}
|
143
src/Response/Webhook.php
Normal file
143
src/Response/Webhook.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace Intuit\Response;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Stores incoming or outgoing message data for a Slack API call.
|
||||
*/
|
||||
class Webhook implements \ArrayAccess, \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var Collection The response data.
|
||||
*/
|
||||
protected Collection $data;
|
||||
|
||||
/**
|
||||
* Creates a new payload object.
|
||||
*
|
||||
* @param array $data The payload data.
|
||||
*/
|
||||
public function __construct(array $data,bool $key=FALSE)
|
||||
{
|
||||
$this->data = collect($key ? ['payload'=>$data ] : $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a response object from a JSON message.
|
||||
*
|
||||
* @param string $json A JSON string.
|
||||
* @return Webhook The parsed response.
|
||||
*/
|
||||
public static function fromJson($json): self
|
||||
{
|
||||
$data = json_decode((string)$json,true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE || (! is_array($data))) {
|
||||
throw new \UnexpectedValueException('Invalid JSON message:'.serialize($data));
|
||||
}
|
||||
|
||||
return new static($data);
|
||||
}
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (is_null($offset)) {
|
||||
$this->data[] = $value;
|
||||
|
||||
} else {
|
||||
$this->data[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->data[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->data[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return null
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->data[$offset] ?? NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
* Return the events of a specific type
|
||||
* @param string $type
|
||||
* @return Collection
|
||||
*/
|
||||
public function event(string $type): Collection
|
||||
{
|
||||
return collect($this->data->get($type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the payload data.
|
||||
*
|
||||
* @return array The payload data.
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the payload to a JSON message.
|
||||
*
|
||||
* @return string A JSON message.
|
||||
*/
|
||||
public function toJson(): string
|
||||
{
|
||||
return json_encode($this->data,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event types
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function types(): Collection
|
||||
{
|
||||
return $this->data->keys();
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ trait CompareAttributes
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key,$value) {
|
||||
if (array_key_exists($key,$this->attributes) && (! $this->isSame($key,$value)))
|
||||
if (! array_key_exists($key,$this->attributes) || (! $this->isSame($key,$value)))
|
||||
parent::__set($key,$value);
|
||||
}
|
||||
|
||||
|
33
src/Traits/ProviderTokenTrait.php
Normal file
33
src/Traits/ProviderTokenTrait.php
Normal 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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user