From b43c9ee59bdc6f6c10bbf245af748b62dcd2910e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Aug 2024 08:24:51 +1000 Subject: [PATCH] Quickbooks settings --- app/DataMapper/QuickbooksSettings.php | 36 ++++++ app/Models/Company.php | 2 +- .../Import/Quickbooks/QuickbooksService.php | 104 +++++++++++++++++- app/Services/Import/Quickbooks/SdkWrapper.php | 11 +- .../Transfomers/ClientTransformer.php | 83 +++++++------- 5 files changed, 189 insertions(+), 47 deletions(-) create mode 100644 app/DataMapper/QuickbooksSettings.php diff --git a/app/DataMapper/QuickbooksSettings.php b/app/DataMapper/QuickbooksSettings.php new file mode 100644 index 000000000000..671112689276 --- /dev/null +++ b/app/DataMapper/QuickbooksSettings.php @@ -0,0 +1,36 @@ + $activities diff --git a/app/Services/Import/Quickbooks/QuickbooksService.php b/app/Services/Import/Quickbooks/QuickbooksService.php index d2a9cdd1bfb5..696c43398cce 100644 --- a/app/Services/Import/Quickbooks/QuickbooksService.php +++ b/app/Services/Import/Quickbooks/QuickbooksService.php @@ -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? + } + } } diff --git a/app/Services/Import/Quickbooks/SdkWrapper.php b/app/Services/Import/Quickbooks/SdkWrapper.php index 4bdb3d9e023c..8441c83587f0 100644 --- a/app/Services/Import/Quickbooks/SdkWrapper.php +++ b/app/Services/Import/Quickbooks/SdkWrapper.php @@ -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); diff --git a/app/Services/Import/Quickbooks/Transfomers/ClientTransformer.php b/app/Services/Import/Quickbooks/Transfomers/ClientTransformer.php index a7bd87be607e..246a65636c2b 100644 --- a/app/Services/Import/Quickbooks/Transfomers/ClientTransformer.php +++ b/app/Services/Import/Quickbooks/Transfomers/ClientTransformer.php @@ -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) {