mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Quickbooks settings
This commit is contained in:
parent
7745d6db17
commit
b43c9ee59b
36
app/DataMapper/QuickbooksSettings.php
Normal file
36
app/DataMapper/QuickbooksSettings.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper;
|
||||
|
||||
/**
|
||||
* QuickbooksSettings.
|
||||
*/
|
||||
class QuickbooksSettings
|
||||
{
|
||||
public string $accessTokenKey;
|
||||
|
||||
public string $refresh_token;
|
||||
|
||||
public string $realmID;
|
||||
|
||||
public int $accessTokenExpiresAt;
|
||||
|
||||
public int $refreshTokenExpiresAt;
|
||||
|
||||
/**
|
||||
* entity client,invoice,quote,purchase_order,vendor,payment
|
||||
* sync true/false
|
||||
* update_record true/false
|
||||
* direction push/pull/birection
|
||||
* */
|
||||
public array $settings = [];
|
||||
}
|
@ -118,7 +118,7 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property string|null $smtp_port
|
||||
* @property string|null $smtp_encryption
|
||||
* @property string|null $smtp_local_domain
|
||||
* @property object|null $quickbooks
|
||||
* @property \App\DataMapper\QuickbooksSettings|null $quickbooks
|
||||
* @property boolean $smtp_verify_peer
|
||||
* @property-read \App\Models\Account $account
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
|
@ -11,9 +11,12 @@
|
||||
|
||||
namespace App\Services\Import\Quickbooks;
|
||||
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use QuickBooksOnline\API\Core\CoreConstants;
|
||||
use QuickBooksOnline\API\DataService\DataService;
|
||||
use App\Services\Import\Quickbooks\Transformers\ClientTransformer;
|
||||
|
||||
// quickbooks_realm_id
|
||||
// quickbooks_refresh_token
|
||||
@ -21,12 +24,24 @@ use QuickBooksOnline\API\DataService\DataService;
|
||||
class QuickbooksService
|
||||
{
|
||||
public DataService $sdk;
|
||||
|
||||
private $entities = [
|
||||
'client' => 'Customer',
|
||||
'invoice' => 'Invoice',
|
||||
'quote' => 'Estimate',
|
||||
'purchase_order' => 'PurchaseOrder',
|
||||
'payment' => 'Payment',
|
||||
'product' => 'Item',
|
||||
];
|
||||
|
||||
private bool $testMode = true;
|
||||
|
||||
private array $settings = [];
|
||||
|
||||
public function __construct(private Company $company)
|
||||
{
|
||||
$this->init();
|
||||
$this->settings = $this->company->quickbooks->settings;
|
||||
}
|
||||
|
||||
private function init(): self
|
||||
@ -64,14 +79,91 @@ class QuickbooksService
|
||||
] : [];
|
||||
}
|
||||
|
||||
public function getSdk(): DataService
|
||||
{
|
||||
return $this->sdk;
|
||||
}
|
||||
|
||||
public function sdk(): SdkWrapper
|
||||
{
|
||||
return new SdkWrapper($this->sdk, $this->company);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* //@todo - refactor to a job
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sync()
|
||||
{
|
||||
//syncable_records.
|
||||
|
||||
foreach($this->entities as $entity)
|
||||
{
|
||||
|
||||
$records = $this->sdk()->fetchRecords($entity);
|
||||
|
||||
$this->processEntitySync($entity, $records);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function processEntitySync(string $entity, $records)
|
||||
{
|
||||
match($entity){
|
||||
'client' => $this->syncQbToNinjaClients($records),
|
||||
// 'vendor' => $this->syncQbToNinjaClients($records),
|
||||
// 'invoice' => $this->syncInvoices($records),
|
||||
// 'quote' => $this->syncInvoices($records),
|
||||
// 'purchase_order' => $this->syncInvoices($records),
|
||||
// 'payment' => $this->syncPayment($records),
|
||||
// 'product' => $this->syncItem($records),
|
||||
};
|
||||
}
|
||||
|
||||
private function syncQbToNinjaClients(array $records)
|
||||
{
|
||||
foreach($records as $record)
|
||||
{
|
||||
$ninja_client_data = new ClientTransformer($record);
|
||||
|
||||
if($client = $this->findClient($ninja_client_data))
|
||||
{
|
||||
$client->fill($ninja_client_data[0]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function findClient(array $qb_data)
|
||||
{
|
||||
$client = $qb_data[0];
|
||||
$contact = $qb_data[1];
|
||||
$client_meta = $qb_data[2];
|
||||
|
||||
$search = Client::query()
|
||||
->withTrashed()
|
||||
->where('company', $this->company->id)
|
||||
->where(function ($q) use ($client, $client_meta, $contact){
|
||||
|
||||
$q->where('client_hash', $client_meta['client_hash'])
|
||||
->orWhere('id_number', $client['id_number'])
|
||||
->orWhereHas('contacts', function ($q) use ($contact){
|
||||
$q->where('email', $contact['email']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
if($search->count() == 0) {
|
||||
//new client
|
||||
$client = ClientFactory::create($this->company->id, $this->company->owner()->id);
|
||||
$client->client_hash = $client_meta['client_hash'];
|
||||
$client->settings = $client_meta['settings'];
|
||||
|
||||
return $client;
|
||||
}
|
||||
elseif($search->count() == 1) {
|
||||
// ? sync / update
|
||||
}
|
||||
else {
|
||||
//potentially multiple matching clients?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,12 +154,17 @@ class SdkWrapper
|
||||
return (int)$this->sdk->Query("select count(*) from $entity");
|
||||
}
|
||||
|
||||
private function queryData(string $query, int $start = 1, $limit = 100): array
|
||||
private function queryData(string $query, int $start = 1, $limit = 1000): array
|
||||
{
|
||||
return (array) $this->sdk->Query($query, $start, $limit);
|
||||
}
|
||||
|
||||
public function fetchRecords(string $entity, int $max = 1000): array
|
||||
public function fetchById(string $entity, $id)
|
||||
{
|
||||
return $this->sdk->FindById($entity, $id);
|
||||
}
|
||||
|
||||
public function fetchRecords(string $entity, int $max = 100000): array
|
||||
{
|
||||
|
||||
if(!in_array($entity, $this->entities)) {
|
||||
@ -168,7 +173,7 @@ class SdkWrapper
|
||||
|
||||
$records = [];
|
||||
$start = 0;
|
||||
$limit = 100;
|
||||
$limit = 1000;
|
||||
try {
|
||||
$total = $this->totalRecords($entity);
|
||||
$total = min($max, $total);
|
||||
|
@ -12,61 +12,70 @@
|
||||
|
||||
namespace App\Services\Import\Quickbooks\Transformers;
|
||||
|
||||
use App\DataMapper\ClientSettings;
|
||||
|
||||
/**
|
||||
* Class ClientTransformer.
|
||||
*/
|
||||
class ClientTransformer
|
||||
{
|
||||
|
||||
private $fillable = [
|
||||
'name' => 'CompanyName',
|
||||
'phone' => 'PrimaryPhone.FreeFormNumber',
|
||||
'country_id' => 'BillAddr.Country',
|
||||
'state' => 'BillAddr.CountrySubDivisionCode',
|
||||
'address1' => 'BillAddr.Line1',
|
||||
'city' => 'BillAddr.City',
|
||||
'postal_code' => 'BillAddr.PostalCode',
|
||||
'shipping_country_id' => 'ShipAddr.Country',
|
||||
'shipping_state' => 'ShipAddr.CountrySubDivisionCode',
|
||||
'shipping_address1' => 'ShipAddr.Line1',
|
||||
'shipping_city' => 'ShipAddr.City',
|
||||
'shipping_postal_code' => 'ShipAddr.PostalCode',
|
||||
'public_notes' => 'Notes'
|
||||
];
|
||||
|
||||
public function __invoke($qb_data)
|
||||
public function __invoke($qb_data): array
|
||||
{
|
||||
return $this->transform($qb_data);
|
||||
}
|
||||
|
||||
|
||||
public function transform($data)
|
||||
public function transform($data): array
|
||||
{
|
||||
$transformed_data = [];
|
||||
// Assuming 'customer_name' is equivalent to 'CompanyName'
|
||||
if (isset($data['CompanyName']) && $this->hasClient($data['CompanyName'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$transformed_data = $this->preTransform($data);
|
||||
$transformed_data['contacts'][0] = $this->getContacts($data)->toArray() + ['company_id' => $this->company->id, 'user_id' => $this->company->owner()->id ];
|
||||
$contact = [
|
||||
'first_name' => data_get($data, 'GivenName'),
|
||||
'last_name' => data_get($data, 'FamilyName'),
|
||||
'phone' => data_get($data, 'PrimaryPhone.FreeFormNumber'),
|
||||
'email' => data_get($data, 'PrimaryEmailAddr.Address'),
|
||||
];
|
||||
|
||||
return $transformed_data;
|
||||
$client = [
|
||||
'name' => data_get($data,'CompanyName', ''),
|
||||
'address1' => data_get($data, 'BillAddr.Line1', ''),
|
||||
'address2' => data_get($data, 'BillAddr.Line2', ''),
|
||||
'city' => data_get($data, 'BillAddr.City', ''),
|
||||
'country_id' => $this->resolveCountry(data_get($data, 'BillAddr.Country', '')),
|
||||
'state' => data_get($data, 'BillAddr.CountrySubDivisionCode', ''),
|
||||
'postal_code' => data_get($data, 'BillAddr.PostalCode', ''),
|
||||
'shipping_address1' => data_get($data, 'ShipAddr.Line1', ''),
|
||||
'shipping_address2' => data_get($data, 'ShipAddr.Line2', ''),
|
||||
'shipping_city' => data_get($data, 'ShipAddr.City', ''),
|
||||
'shipping_country_id' => $this->resolveCountry(data_get($data, 'ShipAddr.Country', '')),
|
||||
'shipping_state' => data_get($data, 'ShipAddr.CountrySubDivisionCode', ''),
|
||||
'shipping_postal_code' => data_get($data, 'BillAddr.PostalCode', ''),
|
||||
'id_number' => data_get($data, 'Id', ''),
|
||||
];
|
||||
|
||||
$settings = ClientSettings::defaults();
|
||||
$settings->currency_id = (string) $this->resolveCurrency(data_get($data, 'CurrencyRef.value'));
|
||||
|
||||
$new_client_merge = [
|
||||
'client_hash' => data_get($data, 'V4IDPseudonym', \Illuminate\Support\Str::random(32)),
|
||||
'settings' => $settings,
|
||||
];
|
||||
|
||||
return [$client, $contact, $new_client_merge];
|
||||
}
|
||||
|
||||
protected function getContacts($data)
|
||||
private function resolveCountry(string $iso_3_code)
|
||||
{
|
||||
return (new ClientContact())->fill([
|
||||
'first_name' => $this->getString($data, 'GivenName'),
|
||||
'last_name' => $this->getString($data, 'FamilyName'),
|
||||
'phone' => $this->getString($data, 'PrimaryPhone.FreeFormNumber'),
|
||||
'email' => $this->getString($data, 'PrimaryEmailAddr.Address'),
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->company->owner()->id,
|
||||
'send_email' => true,
|
||||
]);
|
||||
return (string) app('countries')->first(function ($c) use ($iso_3_code){
|
||||
return $c->iso_3166_3 == $iso_3_code;
|
||||
})->id ?? 840;
|
||||
}
|
||||
|
||||
private function resolveCurrency(string $currency_code)
|
||||
{
|
||||
return (string) app('currencies')->first(function($c) use ($currency_code){
|
||||
return $c->code == $currency_code;
|
||||
}) ?? 'USD';
|
||||
}
|
||||
|
||||
public function getShipAddrCountry($data, $field)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user