mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
minor adjustments
This commit is contained in:
parent
8f82b27e50
commit
7f226fe5d2
@ -93,6 +93,12 @@ class StoreInvoiceRequest extends Request
|
|||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|INVOICE|".$this->input('client_id', '')."|".$user->company()->company_key)) {
|
||||||
|
usleep(200000);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Illuminate\Support\Facades\Cache::put($this->ip()."|INVOICE|".$this->input('client_id', '')."|".$user->company()->company_key,1);
|
||||||
|
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
$input = $this->decodePrimaryKeys($input);
|
$input = $this->decodePrimaryKeys($input);
|
||||||
|
@ -154,7 +154,6 @@ class PaymentRepository extends BaseRepository
|
|||||||
if ($invoice) {
|
if ($invoice) {
|
||||||
|
|
||||||
//25-06-2023
|
//25-06-2023
|
||||||
|
|
||||||
$paymentable = new Paymentable();
|
$paymentable = new Paymentable();
|
||||||
$paymentable->payment_id = $payment->id;
|
$paymentable->payment_id = $payment->id;
|
||||||
$paymentable->paymentable_id = $invoice->id;
|
$paymentable->paymentable_id = $invoice->id;
|
||||||
|
@ -13,11 +13,18 @@ namespace App\Services\Import\Quickbooks;
|
|||||||
|
|
||||||
use App\Factory\ClientContactFactory;
|
use App\Factory\ClientContactFactory;
|
||||||
use App\Factory\ClientFactory;
|
use App\Factory\ClientFactory;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Factory\ProductFactory;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Product;
|
||||||
use QuickBooksOnline\API\Core\CoreConstants;
|
use QuickBooksOnline\API\Core\CoreConstants;
|
||||||
use QuickBooksOnline\API\DataService\DataService;
|
use QuickBooksOnline\API\DataService\DataService;
|
||||||
use App\Services\Import\Quickbooks\Transformers\ClientTransformer;
|
use App\Services\Import\Quickbooks\Transformers\ClientTransformer;
|
||||||
|
use App\Services\Import\Quickbooks\Transformers\InvoiceTransformer;
|
||||||
|
use App\Services\Import\Quickbooks\Transformers\PaymentTransformer;
|
||||||
|
use App\Services\Import\Quickbooks\Transformers\ProductTransformer;
|
||||||
|
|
||||||
// quickbooks_realm_id
|
// quickbooks_realm_id
|
||||||
// quickbooks_refresh_token
|
// quickbooks_refresh_token
|
||||||
@ -27,12 +34,12 @@ class QuickbooksService
|
|||||||
public DataService $sdk;
|
public DataService $sdk;
|
||||||
|
|
||||||
private $entities = [
|
private $entities = [
|
||||||
|
'product' => 'Item',
|
||||||
'client' => 'Customer',
|
'client' => 'Customer',
|
||||||
'invoice' => 'Invoice',
|
'invoice' => 'Invoice',
|
||||||
'quote' => 'Estimate',
|
'quote' => 'Estimate',
|
||||||
'purchase_order' => 'PurchaseOrder',
|
'purchase_order' => 'PurchaseOrder',
|
||||||
'payment' => 'Payment',
|
'payment' => 'Payment',
|
||||||
'product' => 'Item',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private bool $testMode = true;
|
private bool $testMode = true;
|
||||||
@ -101,7 +108,7 @@ class QuickbooksService
|
|||||||
|
|
||||||
$records = $this->sdk()->fetchRecords($entity);
|
$records = $this->sdk()->fetchRecords($entity);
|
||||||
|
|
||||||
nlog($records);
|
nlog(json_encode($records));
|
||||||
|
|
||||||
$this->processEntitySync($key, $records);
|
$this->processEntitySync($key, $records);
|
||||||
|
|
||||||
@ -126,25 +133,96 @@ class QuickbooksService
|
|||||||
|
|
||||||
private function processEntitySync(string $entity, $records)
|
private function processEntitySync(string $entity, $records)
|
||||||
{
|
{
|
||||||
nlog($entity);
|
|
||||||
nlog($records);
|
|
||||||
match($entity){
|
match($entity){
|
||||||
'client' => $this->syncQbToNinjaClients($records),
|
// 'client' => $this->syncQbToNinjaClients($records),
|
||||||
|
// 'product' => $this->syncQbToNinjaProducts($records),
|
||||||
|
'invoice' => $this->syncQbToNinjaInvoices($records),
|
||||||
// 'vendor' => $this->syncQbToNinjaClients($records),
|
// 'vendor' => $this->syncQbToNinjaClients($records),
|
||||||
// 'invoice' => $this->syncInvoices($records),
|
|
||||||
// 'quote' => $this->syncInvoices($records),
|
// 'quote' => $this->syncInvoices($records),
|
||||||
// 'purchase_order' => $this->syncInvoices($records),
|
// 'purchase_order' => $this->syncInvoices($records),
|
||||||
// 'payment' => $this->syncPayment($records),
|
// 'payment' => $this->syncPayment($records),
|
||||||
// 'product' => $this->syncItem($records),
|
|
||||||
default => false,
|
default => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncQbToNinjaClients(array $records)
|
private function syncQbToNinjaInvoices($records): void
|
||||||
{
|
{
|
||||||
nlog("qb => ninja");
|
$invoice_transformer = new InvoiceTransformer($this->company);
|
||||||
|
|
||||||
|
foreach($records as $record)
|
||||||
|
{
|
||||||
|
$ninja_invoice_data = $invoice_transformer->qbToNinja($record);
|
||||||
|
|
||||||
$client_transformer = new ClientTransformer();
|
$payment_ids = $ninja_invoice_data['payment_ids'] ?? [];
|
||||||
|
$client_id = $ninja_invoice_data['client_id'] ?? null;
|
||||||
|
|
||||||
|
if(is_null($client_id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
unset($ninja_invoice_data['payment_ids']);
|
||||||
|
|
||||||
|
if($invoice = $this->findInvoice($ninja_invoice_data))
|
||||||
|
{
|
||||||
|
$invoice->fill($ninja_invoice_data);
|
||||||
|
$invoice->saveQuietly();
|
||||||
|
|
||||||
|
$invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();
|
||||||
|
|
||||||
|
foreach($payment_ids as $payment_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
$payment = $this->sdk->FindById('Payment', $payment_id);
|
||||||
|
$payment_transformer = new PaymentTransformer($this->company);
|
||||||
|
|
||||||
|
$transformed = $payment_transformer->qbToNinja($payment);
|
||||||
|
|
||||||
|
$ninja_payment = $payment_transformer->buildPayment($payment);
|
||||||
|
$ninja_payment->service()->applyNumber()->save();
|
||||||
|
|
||||||
|
$paymentable = new \App\Models\Paymentable();
|
||||||
|
$paymentable->payment_id = $ninja_payment->id;
|
||||||
|
$paymentable->paymentable_id = $invoice->id;
|
||||||
|
$paymentable->paymentable_type = 'invoices';
|
||||||
|
$paymentable->amount = $transformed['applied'];
|
||||||
|
$paymentable->save();
|
||||||
|
|
||||||
|
$invoice->service()->applyPayment($ninja_payment, $transformed['applied']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$ninja_invoice_data = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findInvoice(array $ninja_invoice_data): ?Invoice
|
||||||
|
{
|
||||||
|
$search = Invoice::query()
|
||||||
|
->withTrashed()
|
||||||
|
->where('company_id', $this->company->id)
|
||||||
|
->where('number', $ninja_invoice_data['number']);
|
||||||
|
|
||||||
|
if($search->count() == 0) {
|
||||||
|
//new invoice
|
||||||
|
$invoice = InvoiceFactory::create($this->company->id, $this->company->owner()->id);
|
||||||
|
$invoice->client_id = $ninja_invoice_data['client_id'];
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
} elseif($search->count() == 1) {
|
||||||
|
return $this->settings['invoice']['update_record'] ? $search->first() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function syncQbToNinjaClients(array $records): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$client_transformer = new ClientTransformer($this->company);
|
||||||
|
|
||||||
foreach($records as $record)
|
foreach($records as $record)
|
||||||
{
|
{
|
||||||
@ -176,14 +254,28 @@ class QuickbooksService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function syncQbToNinjaProducts($records): void
|
||||||
|
{
|
||||||
|
$product_transformer = new ProductTransformer($this->company);
|
||||||
|
|
||||||
|
foreach($records as $record)
|
||||||
|
{
|
||||||
|
$ninja_data = $product_transformer->qbToNinja($record);
|
||||||
|
|
||||||
|
if($product = $this->findProduct($ninja_data['product_key']))
|
||||||
|
{
|
||||||
|
$product->fill($ninja_data);
|
||||||
|
$product->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function findClient(array $qb_data) :?Client
|
private function findClient(array $qb_data) :?Client
|
||||||
{
|
{
|
||||||
$client = $qb_data[0];
|
$client = $qb_data[0];
|
||||||
$contact = $qb_data[1];
|
$contact = $qb_data[1];
|
||||||
$client_meta = $qb_data[2];
|
$client_meta = $qb_data[2];
|
||||||
|
|
||||||
nlog($qb_data);
|
|
||||||
|
|
||||||
$search = Client::query()
|
$search = Client::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
@ -208,8 +300,28 @@ class QuickbooksService
|
|||||||
elseif($search->count() == 1) {
|
elseif($search->count() == 1) {
|
||||||
return $this->settings['client']['update_record'] ? $search->first() : null;
|
return $this->settings['client']['update_record'] ? $search->first() : null;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
//potentially multiple matching clients?
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findProduct(string $key): ?Product
|
||||||
|
{
|
||||||
|
$search = Product::query()
|
||||||
|
->withTrashed()
|
||||||
|
->where('company_id', $this->company->id)
|
||||||
|
->where('product_key', $key);
|
||||||
|
|
||||||
|
if($search->count() == 0) {
|
||||||
|
//new product
|
||||||
|
$product = ProductFactory::create($this->company->id, $this->company->owner()->id);
|
||||||
|
|
||||||
|
return $product;
|
||||||
|
} elseif($search->count() == 1) {
|
||||||
|
return $this->settings['product']['update_record'] ? $search->first() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class SdkWrapper
|
|||||||
{
|
{
|
||||||
public const MAXRESULTS = 10000;
|
public const MAXRESULTS = 10000;
|
||||||
|
|
||||||
private $entities = ['Customer','Invoice','Payment','Item'];
|
private $entities = ['Customer','Invoice','Item'];
|
||||||
|
|
||||||
private OAuth2AccessToken $token;
|
private OAuth2AccessToken $token;
|
||||||
|
|
||||||
@ -198,6 +198,7 @@ class SdkWrapper
|
|||||||
nlog("Fetch Quickbooks API Error: {$th->getMessage()}");
|
nlog("Fetch Quickbooks API Error: {$th->getMessage()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlog($records);
|
||||||
return $records;
|
return $records;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services\Import\Quickbooks\Transformers;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Company;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BaseTransformer.
|
||||||
|
*/
|
||||||
|
class BaseTransformer
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(public Company $company)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveCountry(string $iso_3_code): string
|
||||||
|
{
|
||||||
|
/** @var \App\Models\Country $country */
|
||||||
|
$country = app('countries')->first(function ($c) use ($iso_3_code){
|
||||||
|
|
||||||
|
/** @var \App\Models\Country $c */
|
||||||
|
return $c->iso_3166_3 == $iso_3_code;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $country ? (string) $country->id : '840';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveCurrency(string $currency_code): string
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var \App\Models\Currency $currency */
|
||||||
|
$currency = app('currencies')->first(function($c) use ($currency_code){
|
||||||
|
|
||||||
|
/** @var \App\Models\Currency $c */
|
||||||
|
return $c->code == $currency_code;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $currency ? (string) $currency->id : '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getShipAddrCountry($data, $field)
|
||||||
|
{
|
||||||
|
return is_null(($c = $this->getString($data, $field))) ? null : $this->getCountryId($c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBillAddrCountry($data, $field)
|
||||||
|
{
|
||||||
|
return is_null(($c = $this->getString($data, $field))) ? null : $this->getCountryId($c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientId($customer_reference_id): ?int
|
||||||
|
{
|
||||||
|
$client = Client::query()
|
||||||
|
->withTrashed()
|
||||||
|
->where('company_id', $this->company->id)
|
||||||
|
->where('id_number', $customer_reference_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return $client ? $client->id : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -17,13 +17,9 @@ use App\DataMapper\ClientSettings;
|
|||||||
/**
|
/**
|
||||||
* Class ClientTransformer.
|
* Class ClientTransformer.
|
||||||
*/
|
*/
|
||||||
class ClientTransformer
|
class ClientTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function qbToNinja(mixed $qb_data)
|
public function qbToNinja(mixed $qb_data)
|
||||||
{
|
{
|
||||||
return $this->transform($qb_data);
|
return $this->transform($qb_data);
|
||||||
@ -31,7 +27,6 @@ class ClientTransformer
|
|||||||
|
|
||||||
public function ninjaToQb()
|
public function ninjaToQb()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transform(mixed $data): array
|
public function transform(mixed $data): array
|
||||||
@ -72,32 +67,4 @@ class ClientTransformer
|
|||||||
return [$client, $contact, $new_client_merge];
|
return [$client, $contact, $new_client_merge];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resolveCountry(string $iso_3_code)
|
|
||||||
{
|
|
||||||
$country = app('countries')->first(function ($c) use ($iso_3_code){
|
|
||||||
return $c->iso_3166_3 == $iso_3_code;
|
|
||||||
});
|
|
||||||
|
|
||||||
return $country ? (string) $country->id : '840';
|
|
||||||
}
|
|
||||||
|
|
||||||
private function resolveCurrency(string $currency_code)
|
|
||||||
{
|
|
||||||
$currency = app('currencies')->first(function($c) use ($currency_code){
|
|
||||||
return $c->code == $currency_code;
|
|
||||||
});
|
|
||||||
|
|
||||||
return $currency ? (string) $currency->id : '1';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getShipAddrCountry($data, $field)
|
|
||||||
{
|
|
||||||
return is_null(($c = $this->getString($data, $field))) ? null : $this->getCountryId($c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBillAddrCountry($data, $field)
|
|
||||||
{
|
|
||||||
return is_null(($c = $this->getString($data, $field))) ? null : $this->getCountryId($c);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
* Invoice Ninja (https://clientninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
@ -9,192 +10,247 @@
|
|||||||
* @license https://www.elastic.co/licensing/elastic-license
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Import\Transformer\Quickbooks;
|
namespace App\Services\Import\Quickbooks\Transformers;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use Illuminate\Support\Arr;
|
use App\Models\Product;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use App\DataMapper\InvoiceItem;
|
use App\DataMapper\InvoiceItem;
|
||||||
use App\Import\ImportException;
|
|
||||||
use App\Models\Invoice as Model;
|
|
||||||
use App\Import\Transformer\BaseTransformer;
|
|
||||||
use App\Import\Transformer\Quickbooks\CommonTrait;
|
|
||||||
use App\Import\Transformer\Quickbooks\ClientTransformer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class InvoiceTransformer.
|
* Class InvoiceTransformer.
|
||||||
*/
|
*/
|
||||||
class InvoiceTransformer extends BaseTransformer
|
class InvoiceTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
use CommonTrait {
|
|
||||||
transform as preTransform;
|
public function qbToNinja(mixed $qb_data)
|
||||||
|
{
|
||||||
|
return $this->transform($qb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private $fillable = [
|
public function ninjaToQb()
|
||||||
'amount' => "TotalAmt",
|
|
||||||
'line_items' => "Line",
|
|
||||||
'due_date' => "DueDate",
|
|
||||||
'partial' => "Deposit",
|
|
||||||
'balance' => "Balance",
|
|
||||||
'private_notes' => "CustomerMemo",
|
|
||||||
'public_notes' => "CustomerMemo",
|
|
||||||
'number' => "DocNumber",
|
|
||||||
'created_at' => "CreateTime",
|
|
||||||
'updated_at' => "LastUpdatedTime",
|
|
||||||
'payments' => 'LinkedTxn',
|
|
||||||
'status_id' => 'InvoiceStatus',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function __construct($company)
|
|
||||||
{
|
{
|
||||||
parent::__construct($company);
|
|
||||||
|
|
||||||
$this->model = new Model();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInvoiceStatus($data)
|
public function transform($qb_data)
|
||||||
{
|
{
|
||||||
return Invoice::STATUS_SENT;
|
$client_id = $this->getClientId(data_get($qb_data, 'CustomerRef.value', null));
|
||||||
|
|
||||||
|
return $client_id ? [
|
||||||
|
'client_id' => $client_id,
|
||||||
|
'number' => data_get($qb_data, 'DocNumber', false),
|
||||||
|
'date' => data_get($qb_data, 'TxnDate', now()->format('Y-m-d')),
|
||||||
|
'private_notes' => data_get($qb_data, 'PrivateNote', ''),
|
||||||
|
'public_notes' => data_get($qb_data, 'CustomerMemo.value', false),
|
||||||
|
'due_date' => data_get($qb_data, 'DueDate', null),
|
||||||
|
'po_number' => data_get($qb_data, 'PONumber', ""),
|
||||||
|
'partial' => data_get($qb_data, 'Deposit', 0),
|
||||||
|
'line_items' => $this->getLineItems(data_get($qb_data, 'Line', [])),
|
||||||
|
'payment_ids' => $this->getPayments($qb_data),
|
||||||
|
'status_id' => Invoice::STATUS_SENT,
|
||||||
|
'tax_rate1' => $rate = data_get($qb_data,'TxnTaxDetail.TaxLine.TaxLineDetail.TaxPercent', 0),
|
||||||
|
'tax_name1' => $rate > 0 ? "Sales Tax" : "",
|
||||||
|
] : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transform($data)
|
private function getPayments(mixed $qb_data)
|
||||||
{
|
{
|
||||||
return $this->preTransform($data) + $this->getInvoiceClient($data);
|
$payments = [];
|
||||||
}
|
|
||||||
|
|
||||||
public function getTotalAmt($data)
|
nlog("get payments");
|
||||||
{
|
|
||||||
return (float) $this->getString($data, 'TotalAmt');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLine($data)
|
$qb_payments = data_get($qb_data, 'LinkedTxn', false);
|
||||||
{
|
|
||||||
return array_map(function ($item) {
|
|
||||||
return [
|
|
||||||
'description' => $this->getString($item, 'Description'),
|
|
||||||
'product_key' => $this->getString($item, 'Description'),
|
|
||||||
'quantity' => (int) $this->getString($item, 'SalesItemLineDetail.Qty'),
|
|
||||||
'unit_price' => (float) $this->getString($item, 'SalesItemLineDetail.UnitPrice'),
|
|
||||||
'line_total' => (float) $this->getString($item, 'Amount'),
|
|
||||||
'cost' => (float) $this->getString($item, 'SalesItemLineDetail.UnitPrice'),
|
|
||||||
'product_cost' => (float) $this->getString($item, 'SalesItemLineDetail.UnitPrice'),
|
|
||||||
'tax_amount' => (float) $this->getString($item, 'TxnTaxDetail.TotalTax'),
|
|
||||||
];
|
|
||||||
}, array_filter($this->getString($data, 'Line'), function ($item) {
|
|
||||||
return $this->getString($item, 'DetailType') !== 'SubTotalLineDetail';
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getInvoiceClient($data, $field = null)
|
nlog($qb_payments);
|
||||||
{
|
|
||||||
/**
|
|
||||||
* "CustomerRef": {
|
|
||||||
"value": "23",
|
|
||||||
"name": ""Barnett Design
|
|
||||||
},
|
|
||||||
"CustomerMemo": {
|
|
||||||
"value": "Thank you for your business and have a great day!"
|
|
||||||
},
|
|
||||||
"BillAddr": {
|
|
||||||
"Id": "58",
|
|
||||||
"Line1": "Shara Barnett",
|
|
||||||
"Line2": "Barnett Design",
|
|
||||||
"Line3": "19 Main St.",
|
|
||||||
"Line4": "Middlefield, CA 94303",
|
|
||||||
"Lat": "37.4530553",
|
|
||||||
"Long": "-122.1178261"
|
|
||||||
},
|
|
||||||
"ShipAddr": {
|
|
||||||
"Id": "24",
|
|
||||||
"Line1": "19 Main St.",
|
|
||||||
"City": "Middlefield",
|
|
||||||
"CountrySubDivisionCode": "CA",
|
|
||||||
"PostalCode": "94303",
|
|
||||||
"Lat": "37.445013",
|
|
||||||
"Long": "-122.1391443"
|
|
||||||
},"BillEmail": {
|
|
||||||
"Address": "Design@intuit.com"
|
|
||||||
},
|
|
||||||
[
|
|
||||||
'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'
|
|
||||||
];
|
|
||||||
|
|
||||||
*/
|
if(!$qb_payments) {
|
||||||
$bill_address = (object) $this->getString($data, 'BillAddr');
|
|
||||||
$ship_address = $this->getString($data, 'ShipAddr');
|
|
||||||
$customer = explode(" ", $this->getString($data, 'CustomerRef.name'));
|
|
||||||
$customer = ['GivenName' => $customer[0], 'FamilyName' => $customer[1]];
|
|
||||||
$has_company = property_exists($bill_address, 'Line4');
|
|
||||||
$address = $has_company ? $bill_address->Line4 : $bill_address->Line3;
|
|
||||||
$address_1 = substr($address, 0, stripos($address, ','));
|
|
||||||
$address = array_filter([$address_1] + (explode(' ', substr($address, stripos($address, ",") + 1))));
|
|
||||||
$client_id = null;
|
|
||||||
$client =
|
|
||||||
[
|
|
||||||
"CompanyName" => $has_company ? $bill_address->Line2 : $bill_address->Line1,
|
|
||||||
"BillAddr" => array_combine(['City','CountrySubDivisionCode','PostalCode'], array_pad($address, 3, 'N/A')) + ['Line1' => $has_company ? $bill_address->Line3 : $bill_address->Line2 ],
|
|
||||||
"ShipAddr" => $ship_address
|
|
||||||
] + $customer + ['PrimaryEmailAddr' => ['Address' => $this->getString($data, 'BillEmail.Address') ]];
|
|
||||||
if($this->hasClient($client['CompanyName'])) {
|
|
||||||
$client_id = $this->getClient($client['CompanyName'], $this->getString($client, 'PrimaryEmailAddr.Address'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return ['client' => (new ClientTransformer($this->company))->transform($client), 'client_id' => $client_id ];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDueDate($data)
|
|
||||||
{
|
|
||||||
return $this->parseDateOrNull($data, 'DueDate');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDeposit($data)
|
|
||||||
{
|
|
||||||
return (float) $this->getString($data, 'Deposit');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBalance($data)
|
|
||||||
{
|
|
||||||
return (float) $this->getString($data, 'Balance');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCustomerMemo($data)
|
|
||||||
{
|
|
||||||
return $this->getString($data, 'CustomerMemo.value');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDocNumber($data, $field = null)
|
|
||||||
{
|
|
||||||
return sprintf(
|
|
||||||
"%s-%s",
|
|
||||||
$this->getString($data, 'DocNumber'),
|
|
||||||
$this->getString($data, 'Id.value')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLinkedTxn($data)
|
|
||||||
{
|
|
||||||
$payments = $this->getString($data, 'LinkedTxn');
|
|
||||||
if(empty($payments)) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [[
|
if(!is_array($qb_payments) && data_get($qb_payments, 'TxnType', false) == 'Payment'){
|
||||||
'amount' => $this->getTotalAmt($data),
|
nlog([data_get($qb_payments, 'TxnId.value', false)]);
|
||||||
'date' => $this->parseDateOrNull($data, 'TxnDate')
|
return [data_get($qb_payments, 'TxnId.value', false)];
|
||||||
]];
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach($qb_payments as $payment)
|
||||||
|
{
|
||||||
|
if(data_get($payment, 'TxnType', false) == 'Payment')
|
||||||
|
{
|
||||||
|
$payments[] = data_get($payment, 'TxnId.value', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $payments;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getLineItems(mixed $qb_items)
|
||||||
|
{
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
foreach($qb_items as $qb_item)
|
||||||
|
{
|
||||||
|
$item = new InvoiceItem;
|
||||||
|
$item->product_key = data_get($qb_item, 'SalesItemLineDetail.ItemRef.name', '');
|
||||||
|
$item->notes = data_get($qb_item,'Description', '');
|
||||||
|
$item->quantity = data_get($qb_item,'SalesItemLineDetail.Qty', 0);
|
||||||
|
$item->cost = data_get($qb_item, 'SalesItemLineDetail.UnitPrice', 0);
|
||||||
|
$item->discount = data_get($item,'DiscountRate', data_get($qb_item,'DiscountAmount', 0));
|
||||||
|
$item->is_amount_discount = data_get($qb_item,'DiscountAmount', 0) > 0 ? true : false;
|
||||||
|
$item->type_id = stripos(data_get($qb_item, 'ItemAccountRef.name'), 'Service') !== false ? '2' : '1';
|
||||||
|
$item->tax_id = data_get($qb_item, 'TaxCodeRef.value', '') == 'NON' ? Product::PRODUCT_TYPE_EXEMPT : $item->type_id;
|
||||||
|
$item->tax_rate1 = data_get($qb_item,'TaxLineDetail.TaxRateRef.TaxPercent', 0);
|
||||||
|
$item->tax_name1 = $item->tax_rate1 > 0 ? "Sales Tax" : "";
|
||||||
|
$items[] = (object)$item;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlog($items);
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// public function getTotalAmt($data)
|
||||||
|
// {
|
||||||
|
// return (float) $this->getString($data, 'TotalAmt');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getLine($data)
|
||||||
|
// {
|
||||||
|
// return array_map(function ($item) {
|
||||||
|
// return [
|
||||||
|
// 'description' => $this->getString($item, 'Description'),
|
||||||
|
// 'product_key' => $this->getString($item, 'Description'),
|
||||||
|
// 'quantity' => (int) $this->getString($item, 'SalesItemLineDetail.Qty'),
|
||||||
|
// 'unit_price' => (float) $this->getString($item, 'SalesItemLineDetail.UnitPrice'),
|
||||||
|
// 'line_total' => (float) $this->getString($item, 'Amount'),
|
||||||
|
// 'cost' => (float) $this->getString($item, 'SalesItemLineDetail.UnitPrice'),
|
||||||
|
// 'product_cost' => (float) $this->getString($item, 'SalesItemLineDetail.UnitPrice'),
|
||||||
|
// 'tax_amount' => (float) $this->getString($item, 'TxnTaxDetail.TotalTax'),
|
||||||
|
// ];
|
||||||
|
// }, array_filter($this->getString($data, 'Line'), function ($item) {
|
||||||
|
// return $this->getString($item, 'DetailType') !== 'SubTotalLineDetail';
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getInvoiceClient($data, $field = null)
|
||||||
|
// {
|
||||||
|
// /**
|
||||||
|
// * "CustomerRef": {
|
||||||
|
// "value": "23",
|
||||||
|
// "name": ""Barnett Design
|
||||||
|
// },
|
||||||
|
// "CustomerMemo": {
|
||||||
|
// "value": "Thank you for your business and have a great day!"
|
||||||
|
// },
|
||||||
|
// "BillAddr": {
|
||||||
|
// "Id": "58",
|
||||||
|
// "Line1": "Shara Barnett",
|
||||||
|
// "Line2": "Barnett Design",
|
||||||
|
// "Line3": "19 Main St.",
|
||||||
|
// "Line4": "Middlefield, CA 94303",
|
||||||
|
// "Lat": "37.4530553",
|
||||||
|
// "Long": "-122.1178261"
|
||||||
|
// },
|
||||||
|
// "ShipAddr": {
|
||||||
|
// "Id": "24",
|
||||||
|
// "Line1": "19 Main St.",
|
||||||
|
// "City": "Middlefield",
|
||||||
|
// "CountrySubDivisionCode": "CA",
|
||||||
|
// "PostalCode": "94303",
|
||||||
|
// "Lat": "37.445013",
|
||||||
|
// "Long": "-122.1391443"
|
||||||
|
// },"BillEmail": {
|
||||||
|
// "Address": "Design@intuit.com"
|
||||||
|
// },
|
||||||
|
// [
|
||||||
|
// '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'
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// */
|
||||||
|
// $bill_address = (object) $this->getString($data, 'BillAddr');
|
||||||
|
// $ship_address = $this->getString($data, 'ShipAddr');
|
||||||
|
// $customer = explode(" ", $this->getString($data, 'CustomerRef.name'));
|
||||||
|
// $customer = ['GivenName' => $customer[0], 'FamilyName' => $customer[1]];
|
||||||
|
// $has_company = property_exists($bill_address, 'Line4');
|
||||||
|
// $address = $has_company ? $bill_address->Line4 : $bill_address->Line3;
|
||||||
|
// $address_1 = substr($address, 0, stripos($address, ','));
|
||||||
|
// $address = array_filter([$address_1] + (explode(' ', substr($address, stripos($address, ",") + 1))));
|
||||||
|
// $client_id = null;
|
||||||
|
// $client =
|
||||||
|
// [
|
||||||
|
// "CompanyName" => $has_company ? $bill_address->Line2 : $bill_address->Line1,
|
||||||
|
// "BillAddr" => array_combine(['City','CountrySubDivisionCode','PostalCode'], array_pad($address, 3, 'N/A')) + ['Line1' => $has_company ? $bill_address->Line3 : $bill_address->Line2 ],
|
||||||
|
// "ShipAddr" => $ship_address
|
||||||
|
// ] + $customer + ['PrimaryEmailAddr' => ['Address' => $this->getString($data, 'BillEmail.Address') ]];
|
||||||
|
// if($this->hasClient($client['CompanyName'])) {
|
||||||
|
// $client_id = $this->getClient($client['CompanyName'], $this->getString($client, 'PrimaryEmailAddr.Address'));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// return ['client' => (new ClientTransformer($this->company))->transform($client), 'client_id' => $client_id ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getDueDate($data)
|
||||||
|
// {
|
||||||
|
// return $this->parseDateOrNull($data, 'DueDate');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getDeposit($data)
|
||||||
|
// {
|
||||||
|
// return (float) $this->getString($data, 'Deposit');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getBalance($data)
|
||||||
|
// {
|
||||||
|
// return (float) $this->getString($data, 'Balance');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getCustomerMemo($data)
|
||||||
|
// {
|
||||||
|
// return $this->getString($data, 'CustomerMemo.value');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getDocNumber($data, $field = null)
|
||||||
|
// {
|
||||||
|
// return sprintf(
|
||||||
|
// "%s-%s",
|
||||||
|
// $this->getString($data, 'DocNumber'),
|
||||||
|
// $this->getString($data, 'Id.value')
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getLinkedTxn($data)
|
||||||
|
// {
|
||||||
|
// $payments = $this->getString($data, 'LinkedTxn');
|
||||||
|
// if(empty($payments)) {
|
||||||
|
// return [];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return [[
|
||||||
|
// 'amount' => $this->getTotalAmt($data),
|
||||||
|
// 'date' => $this->parseDateOrNull($data, 'TxnDate')
|
||||||
|
// ]];
|
||||||
|
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://Paymentninja.com).
|
* Invoice Ninja (https://Paymentninja.com).
|
||||||
*
|
*
|
||||||
@ -10,15 +9,11 @@
|
|||||||
* @license https://www.elastic.co/licensing/elastic-license
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Import\Transformer\Quickbooks;
|
namespace App\Services\Import\Quickbooks\Transformers;
|
||||||
|
|
||||||
use App\Import\Transformer\Quickbooks\CommonTrait;
|
use App\Models\Company;
|
||||||
use App\Import\Transformer\BaseTransformer;
|
use App\Models\Payment;
|
||||||
use App\Models\Payment as Model;
|
use App\Factory\PaymentFactory;
|
||||||
use App\Import\ImportException;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use App\Models\Invoice;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -26,45 +21,48 @@ use App\Models\Invoice;
|
|||||||
*/
|
*/
|
||||||
class PaymentTransformer extends BaseTransformer
|
class PaymentTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
use CommonTrait;
|
|
||||||
|
|
||||||
protected $fillable = [
|
public function qbToNinja(mixed $qb_data)
|
||||||
'number' => "PaymentRefNum",
|
|
||||||
'amount' => "TotalAmt",
|
|
||||||
"client_id" => "CustomerRef",
|
|
||||||
"currency_id" => "CurrencyRef",
|
|
||||||
'date' => "TxnDate",
|
|
||||||
"invoices" => "Line",
|
|
||||||
'private_notes' => "PrivateNote",
|
|
||||||
'created_at' => "CreateTime",
|
|
||||||
'updated_at' => "LastUpdatedTime"
|
|
||||||
];
|
|
||||||
|
|
||||||
public function __construct($company)
|
|
||||||
{
|
{
|
||||||
parent::__construct($company);
|
return $this->transform($qb_data);
|
||||||
|
|
||||||
$this->model = new Model();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTotalAmt($data, $field = null)
|
public function ninjaToQb()
|
||||||
{
|
{
|
||||||
return (float) $this->getString($data, $field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTxnDate($data, $field = null)
|
public function transform(mixed $qb_data)
|
||||||
{
|
{
|
||||||
return $this->parseDateOrNull($data, $field);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCustomerRef($data, $field = null)
|
return [
|
||||||
{
|
'date' => data_get($qb_data, 'TxnDate', now()->format('Y-m-d')),
|
||||||
return $this->getClient($this->getString($data, 'CustomerRef.name'), null);
|
'amount' => floatval(data_get($qb_data, 'TotalAmt', 0)),
|
||||||
|
'applied' => data_get($qb_data, 'TotalAmt', 0) - data_get($qb_data, 'UnappliedAmt', 0),
|
||||||
|
'number' => data_get($qb_data, 'DocNumber', null),
|
||||||
|
'private_notes' => data_get($qb_data, 'PrivateNote', null),
|
||||||
|
'currency_id' => (string) $this->resolveCurrency(data_get($qb_data, 'CurrencyRef.value')),
|
||||||
|
'client_id' => $this->getClientId(data_get($qb_data, 'CustomerRef.value', null)),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCurrencyRef($data, $field = null)
|
public function buildPayment($qb_data): ?Payment
|
||||||
{
|
{
|
||||||
return $this->getCurrencyByCode($data['CurrencyRef'], 'value');
|
$ninja_payment_data = $this->transform($qb_data);
|
||||||
|
|
||||||
|
if($ninja_payment_data['client_id'])
|
||||||
|
{
|
||||||
|
$payment = PaymentFactory::create($this->company->id, $this->company->owner()->id,$ninja_payment_data['client_id']);
|
||||||
|
$payment->amount = $ninja_payment_data['amount'];
|
||||||
|
$payment->applied = $ninja_payment_data['applied'];
|
||||||
|
$payment->status_id = 4;
|
||||||
|
$payment->fill($ninja_payment_data);
|
||||||
|
|
||||||
|
$payment->client->service()->updatePaidToDate($payment->amount);
|
||||||
|
|
||||||
|
return $payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLine($data, $field = null)
|
public function getLine($data, $field = null)
|
||||||
@ -84,23 +82,4 @@ class PaymentTransformer extends BaseTransformer
|
|||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $invoice_number
|
|
||||||
*
|
|
||||||
* @return int|null
|
|
||||||
*/
|
|
||||||
public function getInvoiceId($invoice_number)
|
|
||||||
{
|
|
||||||
$invoice = Invoice::query()->where('company_id', $this->company->id)
|
|
||||||
->where('is_deleted', false)
|
|
||||||
->where(
|
|
||||||
"number",
|
|
||||||
"LIKE",
|
|
||||||
"%-$invoice_number%",
|
|
||||||
)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
return $invoice ? $invoice->id : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://Productninja.com).
|
* Invoice Ninja (https://clientninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
@ -10,52 +10,35 @@
|
|||||||
* @license https://www.elastic.co/licensing/elastic-license
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Import\Transformer\Quickbooks;
|
namespace App\Services\Import\Quickbooks\Transformers;
|
||||||
|
|
||||||
use App\Import\Transformer\Quickbooks\CommonTrait;
|
|
||||||
use App\Import\Transformer\BaseTransformer;
|
|
||||||
use App\Models\Product as Model;
|
|
||||||
use App\Import\ImportException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ProductTransformer.
|
* Class ProductTransformer.
|
||||||
*/
|
*/
|
||||||
class ProductTransformer extends BaseTransformer
|
class ProductTransformer extends BaseTransformer
|
||||||
{
|
{
|
||||||
use CommonTrait;
|
|
||||||
|
|
||||||
protected $fillable = [
|
public function qbToNinja(mixed $qb_data)
|
||||||
'product_key' => 'Name',
|
|
||||||
'notes' => 'Description',
|
|
||||||
'cost' => 'PurchaseCost',
|
|
||||||
'price' => 'UnitPrice',
|
|
||||||
'quantity' => 'QtyOnHand',
|
|
||||||
'in_stock_quantity' => 'QtyOnHand',
|
|
||||||
'created_at' => 'CreateTime',
|
|
||||||
'updated_at' => 'LastUpdatedTime',
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct($company)
|
|
||||||
{
|
{
|
||||||
parent::__construct($company);
|
return $this->transform($qb_data);
|
||||||
|
|
||||||
$this->model = new Model();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQtyOnHand($data, $field = null)
|
public function ninjaToQb()
|
||||||
{
|
{
|
||||||
return (int) $this->getString($data, $field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPurchaseCost($data, $field = null)
|
public function transform(mixed $data): array
|
||||||
{
|
{
|
||||||
return (float) $this->getString($data, $field);
|
|
||||||
|
return [
|
||||||
|
'product_key' => data_get($data, 'Name', data_get($data, 'FullyQualifiedName','')),
|
||||||
|
'notes' => data_get($data, 'Description', ''),
|
||||||
|
'cost' => data_get($data, 'PurchaseCost', 0),
|
||||||
|
'price' => data_get($data, 'UnitPrice', 0),
|
||||||
|
'in_stock_quantity' => data_get($data, 'QtyOnHand', 0),
|
||||||
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getUnitPrice($data, $field = null)
|
|
||||||
{
|
|
||||||
return (float) $this->getString($data, $field);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,8 @@ class InvoiceService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a payment amount to an invoice.
|
* Apply a payment amount to an invoice.
|
||||||
|
*
|
||||||
|
* *** does not create a paymentable ****
|
||||||
* @param Payment $payment The Payment
|
* @param Payment $payment The Payment
|
||||||
* @param float $payment_amount The Payment amount
|
* @param float $payment_amount The Payment amount
|
||||||
* @return InvoiceService Parent class object
|
* @return InvoiceService Parent class object
|
||||||
|
@ -103,7 +103,6 @@ class MarkPaid extends AbstractService
|
|||||||
$this->invoice
|
$this->invoice
|
||||||
->service()
|
->service()
|
||||||
->applyNumber()
|
->applyNumber()
|
||||||
// ->deletePdf()
|
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
$payment->ledger()
|
$payment->ledger()
|
||||||
|
@ -30,110 +30,11 @@ class QuickbooksTest extends TestCase
|
|||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->markTestSkipped("NO BUENO");
|
|
||||||
$this->withoutMiddleware(ThrottleRequests::class);
|
|
||||||
config(['database.default' => config('ninja.db.default')]);
|
|
||||||
$this->makeTestData();
|
|
||||||
//
|
|
||||||
$this->withoutExceptionHandling();
|
|
||||||
Auth::setUser($this->user);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testImportCallsGetDataOnceForClient()
|
public function testCustomerSync()
|
||||||
{
|
{
|
||||||
$data = (json_decode(file_get_contents(base_path('tests/Feature/Import/customers.json')), true))['Customer'];
|
$data = (json_decode(file_get_contents(base_path('tests/Feature/Import/Quickbooks/customers.json')), false));
|
||||||
$hash = Str::random(32);
|
|
||||||
Cache::put($hash.'-client', base64_encode(json_encode($data)), 360);
|
|
||||||
|
|
||||||
$quickbooks = Mockery::mock(Quickbooks::class, [[
|
|
||||||
'hash' => $hash,
|
|
||||||
'column_map' => ['client' => ['mapping' => []]],
|
|
||||||
'skip_header' => true,
|
|
||||||
'import_type' => 'quickbooks',
|
|
||||||
], $this->company ])->makePartial();
|
|
||||||
$quickbooks->shouldReceive('getData')
|
|
||||||
->once()
|
|
||||||
->with('client')
|
|
||||||
->andReturn($data);
|
|
||||||
|
|
||||||
// Mocking the dependencies used within the client method
|
|
||||||
|
|
||||||
$quickbooks->import('client');
|
|
||||||
|
|
||||||
$this->assertArrayHasKey('clients', $quickbooks->entity_count);
|
|
||||||
$this->assertGreaterThan(0, $quickbooks->entity_count['clients']);
|
|
||||||
|
|
||||||
$base_transformer = new BaseTransformer($this->company);
|
|
||||||
$this->assertTrue($base_transformer->hasClient('Sonnenschein Family Store'));
|
|
||||||
$contact = $base_transformer->getClient('Amy\'s Bird Sanctuary', '');
|
|
||||||
$contact = Client::where('name', 'Amy\'s Bird Sanctuary')->first();
|
|
||||||
$this->assertEquals('(650) 555-3311', $contact->phone);
|
|
||||||
$this->assertEquals('Birds@Intuit.com', $contact->contacts()->first()->email);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testImportCallsGetDataOnceForProducts()
|
|
||||||
{
|
|
||||||
$data = (json_decode(file_get_contents(base_path('tests/Feature/Import/items.json')), true))['Item'];
|
|
||||||
$hash = Str::random(32);
|
|
||||||
Cache::put($hash.'-item', base64_encode(json_encode($data)), 360);
|
|
||||||
|
|
||||||
$quickbooks = Mockery::mock(Quickbooks::class, [[
|
|
||||||
'hash' => $hash,
|
|
||||||
'column_map' => ['item' => ['mapping' => []]],
|
|
||||||
'skip_header' => true,
|
|
||||||
'import_type' => 'quickbooks',
|
|
||||||
], $this->company ])->makePartial();
|
|
||||||
$quickbooks->shouldReceive('getData')
|
|
||||||
->once()
|
|
||||||
->with('product')
|
|
||||||
->andReturn($data);
|
|
||||||
|
|
||||||
// Mocking the dependencies used within the client method
|
|
||||||
|
|
||||||
$quickbooks->import('product');
|
|
||||||
|
|
||||||
$this->assertArrayHasKey('products', $quickbooks->entity_count);
|
|
||||||
$this->assertGreaterThan(0, $quickbooks->entity_count['products']);
|
|
||||||
|
|
||||||
$base_transformer = new BaseTransformer($this->company);
|
|
||||||
$this->assertTrue($base_transformer->hasProduct('Gardening'));
|
|
||||||
$product = Product::where('product_key', 'Pest Control')->first();
|
|
||||||
$this->assertGreaterThanOrEqual(35, $product->price);
|
|
||||||
$this->assertLessThanOrEqual(0, $product->quantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testImportCallsGetDataOnceForInvoices()
|
|
||||||
{
|
|
||||||
$data = (json_decode(file_get_contents(base_path('tests/Feature/Import/invoices.json')), true))['Invoice'];
|
|
||||||
$hash = Str::random(32);
|
|
||||||
Cache::put($hash.'-invoice', base64_encode(json_encode($data)), 360);
|
|
||||||
$quickbooks = Mockery::mock(Quickbooks::class, [[
|
|
||||||
'hash' => $hash,
|
|
||||||
'column_map' => ['invoice' => ['mapping' => []]],
|
|
||||||
'skip_header' => true,
|
|
||||||
'import_type' => 'quickbooks',
|
|
||||||
], $this->company ])->makePartial();
|
|
||||||
$quickbooks->shouldReceive('getData')
|
|
||||||
->once()
|
|
||||||
->with('invoice')
|
|
||||||
->andReturn($data);
|
|
||||||
$quickbooks->import('invoice');
|
|
||||||
$this->assertArrayHasKey('invoices', $quickbooks->entity_count);
|
|
||||||
$this->assertGreaterThan(0, $quickbooks->entity_count['invoices']);
|
|
||||||
$base_transformer = new BaseTransformer($this->company);
|
|
||||||
$this->assertTrue($base_transformer->hasInvoice(1007));
|
|
||||||
$invoice = Invoice::where('number', 1012)->first();
|
|
||||||
$data = collect($data)->where('DocNumber', '1012')->first();
|
|
||||||
$this->assertGreaterThanOrEqual($data['TotalAmt'], $invoice->amount);
|
|
||||||
$this->assertEquals(count($data['Line']) - 1, count((array)$invoice->line_items));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
Mockery::close();
|
|
||||||
parent::tearDown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11675
tests/Feature/Import/Quickbooks/customer.json
Normal file
11675
tests/Feature/Import/Quickbooks/customer.json
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user