From d3a9fb9dd779e5acbe049b6435142a21d65c6fd9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 08:09:20 +1000 Subject: [PATCH 01/10] Add client to recurring invoice transformer --- app/Transformers/RecurringInvoiceTransformer.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/Transformers/RecurringInvoiceTransformer.php b/app/Transformers/RecurringInvoiceTransformer.php index ce55314599cf..17f3c2e47b00 100644 --- a/app/Transformers/RecurringInvoiceTransformer.php +++ b/app/Transformers/RecurringInvoiceTransformer.php @@ -13,11 +13,13 @@ namespace App\Transformers; use App\Models\Activity; use App\Models\Backup; +use App\Models\Client; use App\Models\Document; use App\Models\Invoice; use App\Models\RecurringInvoice; use App\Models\RecurringInvoiceInvitation; use App\Transformers\ActivityTransformer; +use App\Transformers\ClientTransformer; use App\Transformers\InvoiceHistoryTransformer; use App\Utils\Traits\MakesHash; @@ -32,6 +34,7 @@ class RecurringInvoiceTransformer extends EntityTransformer protected $availableIncludes = [ 'activities', + 'client', ]; public function includeHistory(RecurringInvoice $invoice) @@ -62,6 +65,13 @@ class RecurringInvoiceTransformer extends EntityTransformer return $this->includeCollection($invoice->documents, $transformer, Document::class); } + public function includeClient(RecurringInvoice $invoice) + { + $transformer = new ClientTransformer($this->serializer); + + return $this->includeItem($invoice->client, $transformer, Client::class); + } + public function transform(RecurringInvoice $invoice) { From 9f47187cdb55f3a92c387d91760e98a4fb7ef605 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 11:02:31 +1000 Subject: [PATCH 02/10] Contact export --- app/Export/CSV/ClientExport.php | 3 +- app/Export/CSV/ContactExport.php | 177 +++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 app/Export/CSV/ContactExport.php diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index 3abb7e92db64..d6bcbb941f9c 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -112,8 +112,7 @@ class ClientExport }); - echo $this->csv->toString(); - + return $this->csv->toString(); } diff --git a/app/Export/CSV/ContactExport.php b/app/Export/CSV/ContactExport.php new file mode 100644 index 000000000000..d24c7a5d1c23 --- /dev/null +++ b/app/Export/CSV/ContactExport.php @@ -0,0 +1,177 @@ + 'client.address1', + 'address2' => 'client.address2', + 'balance' => 'client.balance', + 'city' => 'client.city', + 'country' => 'client.country_id', + 'credit_balance' => 'client.credit_balance', + 'custom_value1' => 'client.custom_value1', + 'custom_value2' => 'client.custom_value2', + 'custom_value3' => 'client.custom_value3', + 'custom_value4' => 'client.custom_value4', + 'id_number' => 'client.id_number', + 'industry' => 'client.industry_id', + 'last_login' => 'client.last_login', + 'name' => 'client.name', + 'number' => 'client.number', + 'paid_to_date' => 'client.paid_to_date', + 'phone' => 'client.phone', + 'postal_code' => 'client.postal_code', + 'private_notes' => 'client.private_notes', + 'public_notes' => 'client.public_notes', + 'shipping_address1' => 'client.shipping_address1', + 'shipping_address2' => 'client.shipping_address2', + 'shipping_city' => 'client.shipping_city', + 'shipping_country' => 'client.shipping_country_id', + 'shipping_postal_code' => 'client.shipping_postal_code', + 'shipping_state' => 'client.shipping_state', + 'state' => 'client.state', + 'vat_number' => 'client.vat_number', + 'website' => 'client.website', + 'currency' => 'client.currency', + 'first_name' => 'contact.first_name', + 'last_name' => 'contact.last_name', + 'phone' => 'contact.phone', + 'contact_custom_value1' => 'contact.custom_value1', + 'contact_custom_value2' => 'contact.custom_value2', + 'contact_custom_value3' => 'contact.custom_value3', + 'contact_custom_value4' => 'contact.custom_value4', + 'email' => 'contact.email', + ]; + + private array $decorate_keys = [ + 'client.country_id', + 'client.shipping_country_id', + 'client.currency', + 'client.industry', + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->client_transformer = new ClientTransformer(); + $this->contact_transformer = new ClientContactTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + ClientContact::where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($contact){ + + $this->csv->insertOne($this->buildRow($contact)); + + }); + + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(ClientContact $contact) :array + { + + $transformed_contact = false; + + $transformed_client = $this->client_transformer->transform($contact->client); + $transformed_contact = $this->contact_transformer->transform($contact); + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $parts = explode(".",$key); + $entity[$parts[1]] = ""; + + if($parts[0] == 'client') { + $entity[$parts[1]] = $transformed_client[$parts[1]]; + } + elseif($parts[0] == 'contact') { + $entity[$parts[1]] = $transformed_contact[$parts[1]]; + } + + } + + return $this->decorateAdvancedFields($contact->client, $entity); + + } + + private function decorateAdvancedFields(Client $client, array $entity) :array + { + + if(array_key_exists('country_id', $entity)) + $entity['country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : ""; + + if(array_key_exists('shipping_country_id', $entity)) + $entity['shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : ""; + + if(array_key_exists('currency', $entity)) + $entity['currency'] = $client->currency()->code; + + if(array_key_exists('industry_id', $entity)) + $entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : ""; + + return $entity; + } + +} From 161e0e0ee3362e8c6d97dc8ae0d67ae338034275 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 11:14:56 +1000 Subject: [PATCH 03/10] Contact report --- app/Export/CSV/ContactExport.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Export/CSV/ContactExport.php b/app/Export/CSV/ContactExport.php index d24c7a5d1c23..6376a72a4f73 100644 --- a/app/Export/CSV/ContactExport.php +++ b/app/Export/CSV/ContactExport.php @@ -104,7 +104,6 @@ class ContactExport $this->csv->insertOne($this->buildHeader()); ClientContact::where('company_id', $this->company->id) - ->where('is_deleted',0) ->cursor() ->each(function ($contact){ From 56a210924bcc2e3e43163a60b14f7e32f5b0835c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 11:25:53 +1000 Subject: [PATCH 04/10] Credit Exporter --- app/Export/CSV/ClientExport.php | 1 - app/Export/CSV/ContactExport.php | 1 - app/Export/CSV/CreditExport.php | 168 +++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 app/Export/CSV/CreditExport.php diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index d6bcbb941f9c..1bb24ab057ef 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -11,7 +11,6 @@ namespace App\Export\CSV; -use App\Http\Controllers\ClientPortal\setLocale; use App\Libraries\MultiDB; use App\Models\Client; use App\Models\Company; diff --git a/app/Export/CSV/ContactExport.php b/app/Export/CSV/ContactExport.php index 6376a72a4f73..527774f12d9e 100644 --- a/app/Export/CSV/ContactExport.php +++ b/app/Export/CSV/ContactExport.php @@ -11,7 +11,6 @@ namespace App\Export\CSV; -use App\Http\Controllers\ClientPortal\setLocale; use App\Libraries\MultiDB; use App\Models\Client; use App\Models\ClientContact; diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php new file mode 100644 index 000000000000..95160f43dc41 --- /dev/null +++ b/app/Export/CSV/CreditExport.php @@ -0,0 +1,168 @@ + 'amount', + 'balance' => 'balance', + 'client' => 'client_id', + 'custom_surcharge1' => 'custom_surcharge1', + 'custom_surcharge2' => 'custom_surcharge2', + 'custom_surcharge3' => 'custom_surcharge3', + 'custom_surcharge4' => 'custom_surcharge4', + 'country' => 'client.country_id', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'date' => 'date', + 'discount' => 'discount', + 'due_date' => 'due_date', + 'exchange_rate' => 'exchange_rate', + 'footer' => 'footer', + 'invoice' => 'invoice_id', + 'number' => 'number', + 'paid_to_date' => 'paid_to_date', + 'partial' => 'partial', + 'partial_due_date' => 'partial_due_date', + 'po_number' => 'po_number', + 'private_notes' => 'private_notes', + 'public_notes' => 'public_notes', + 'status' => 'status_id', + 'tax_name1' => 'tax_name1', + 'tax_name2' => 'tax_name2', + 'tax_name3' => 'tax_name3', + 'tax_rate1' => 'tax_rate1', + 'tax_rate1' => 'tax_rate1', + 'tax_rate1' => 'tax_rate1', + ]; + + private array $decorate_keys = [ + 'client.country_id', + 'client.shipping_country_id', + 'client.currency', + 'client.industry', + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->credit_transformer = new CreditTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Client::with('contacts')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($client){ + + $this->csv->insertOne($this->buildRow($client)); + + }); + + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(Client $client) :array + { + + $transformed_contact = false; + + $transformed_client = $this->client_transformer->transform($client); + + if($contact = $client->contacts()->first()) + $transformed_contact = $this->contact_transformer->transform($contact); + + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $parts = explode(".",$key); + $entity[$parts[1]] = ""; + + if($parts[0] == 'client') { + $entity[$parts[1]] = $transformed_client[$parts[1]]; + } + elseif($parts[0] == 'contact') { + $entity[$parts[1]] = $transformed_contact[$parts[1]]; + } + + } + + return $this->decorateAdvancedFields($client, $entity); + + } + + private function decorateAdvancedFields(Client $client, array $entity) :array + { + + if(array_key_exists('country_id', $entity)) + $entity['country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : ""; + + if(array_key_exists('shipping_country_id', $entity)) + $entity['shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : ""; + + if(array_key_exists('currency', $entity)) + $entity['currency'] = $client->currency()->code; + + if(array_key_exists('industry_id', $entity)) + $entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : ""; + + return $entity; + } + +} From d1ae7d88d94e1a3667adfd3ec5c404353842f260 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 11:54:17 +1000 Subject: [PATCH 05/10] Document Export --- app/Export/CSV/CreditExport.php | 69 ++++++++---------- app/Export/CSV/DocumentExport.php | 115 ++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 40 deletions(-) create mode 100644 app/Export/CSV/DocumentExport.php diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index 95160f43dc41..e9dbca9e524b 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -14,6 +14,7 @@ namespace App\Export\CSV; use App\Libraries\MultiDB; use App\Models\Client; use App\Models\Company; +use App\Models\Credit; use App\Transformers\CreditTransformer; use App\Utils\Ninja; use Illuminate\Support\Facades\App; @@ -35,7 +36,7 @@ class CreditExport 'custom_surcharge2' => 'custom_surcharge2', 'custom_surcharge3' => 'custom_surcharge3', 'custom_surcharge4' => 'custom_surcharge4', - 'country' => 'client.country_id', + 'country' => 'country_id', 'custom_value1' => 'custom_value1', 'custom_value2' => 'custom_value2', 'custom_value3' => 'custom_value3', @@ -58,15 +59,18 @@ class CreditExport 'tax_name2' => 'tax_name2', 'tax_name3' => 'tax_name3', 'tax_rate1' => 'tax_rate1', - 'tax_rate1' => 'tax_rate1', - 'tax_rate1' => 'tax_rate1', + 'tax_rate2' => 'tax_rate2', + 'tax_rate3' => 'tax_rate3', + 'terms' => 'terms', + 'total_taxes' => 'total_taxes', + 'currency' => 'currency' ]; private array $decorate_keys = [ - 'client.country_id', - 'client.shipping_country_id', - 'client.currency', - 'client.industry', + 'country', + 'client', + 'invoice', + 'currency', ]; public function __construct(Company $company, array $report_keys) @@ -91,14 +95,14 @@ class CreditExport //insert the header $this->csv->insertOne($this->buildHeader()); - Client::with('contacts')->where('company_id', $this->company->id) - ->where('is_deleted',0) - ->cursor() - ->each(function ($client){ + Credit::with('client')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($credit){ - $this->csv->insertOne($this->buildRow($client)); + $this->csv->insertOne($this->buildRow($credit)); - }); + }); return $this->csv->toString(); @@ -116,51 +120,36 @@ class CreditExport return $header; } - private function buildRow(Client $client) :array + private function buildRow(Credit $credit) :array { - $transformed_contact = false; - - $transformed_client = $this->client_transformer->transform($client); - - if($contact = $client->contacts()->first()) - $transformed_contact = $this->contact_transformer->transform($contact); - + $transformed_credit = $this->credit_transformer->transform($credit); $entity = []; foreach(array_values($this->report_keys) as $key){ - $parts = explode(".",$key); - $entity[$parts[1]] = ""; - - if($parts[0] == 'client') { - $entity[$parts[1]] = $transformed_client[$parts[1]]; - } - elseif($parts[0] == 'contact') { - $entity[$parts[1]] = $transformed_contact[$parts[1]]; - } - + $entity[$key] = $transformed_credit[$key]; } - return $this->decorateAdvancedFields($client, $entity); + return $this->decorateAdvancedFields($credit, $entity); } - private function decorateAdvancedFields(Client $client, array $entity) :array + private function decorateAdvancedFields(Credit $credit, array $entity) :array { if(array_key_exists('country_id', $entity)) - $entity['country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : ""; - - if(array_key_exists('shipping_country_id', $entity)) - $entity['shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : ""; + $entity['country_id'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : ""; if(array_key_exists('currency', $entity)) - $entity['currency'] = $client->currency()->code; + $entity['currency'] = $credit->client->currency()->code; - if(array_key_exists('industry_id', $entity)) - $entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : ""; + if(array_key_exists('invoice_id', $entity)) + $entity['invoice_id'] = $credit->invoice ? $credit->invoice->number : ""; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $credit->client->present()->name(); return $entity; } diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php new file mode 100644 index 000000000000..531ae9664ec8 --- /dev/null +++ b/app/Export/CSV/DocumentExport.php @@ -0,0 +1,115 @@ + 'record_type', + 'record_name' => 'record_name', + 'name' => 'name', + 'type' => 'type', + 'created_at' => 'created_at', + ]; + + private array $decorate_keys = [ + + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->entity_transformer = new DocumentTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Document::where('company_id', $this->company->id) + ->cursor() + ->each(function ($entity){ + + $this->csv->insertOne($this->buildRow($entity)); + + }); + + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(Document $document) :array + { + + $transformed_entity = $this->entity_transformer->transform($document); + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $entity[$key] = $transformed_entity[$key]; + } + + return $this->decorateAdvancedFields($document, $entity); + + } + + private function decorateAdvancedFields(Document $document, array $entity) :array + { + + // if(array_key_exists('country_id', $entity)) + // $entity['country_id'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : ""; + + return $entity; + } + +} From ace76b8587f491a0cf18b7c8098263c242320276 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 12:04:33 +1000 Subject: [PATCH 06/10] Document Export --- app/Export/CSV/DocumentExport.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index 531ae9664ec8..28cd752c69d4 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -96,7 +96,8 @@ class DocumentExport foreach(array_values($this->report_keys) as $key){ - $entity[$key] = $transformed_entity[$key]; + $entity[$key] = $transformed_entity[$key]; + } return $this->decorateAdvancedFields($document, $entity); @@ -106,8 +107,11 @@ class DocumentExport private function decorateAdvancedFields(Document $document, array $entity) :array { - // if(array_key_exists('country_id', $entity)) - // $entity['country_id'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : ""; + if(array_key_exists('record_type', $entity)) + $entity['record_type'] = class_basename($document->documentable); + + if(array_key_exists('record_name', $entity)) + $entity['record_name'] = $document->hashed_id; return $entity; } From 6ac34ac5a1df44b1c0edfeefdb8710bcf89947fb Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 14:47:10 +1000 Subject: [PATCH 07/10] fixes for invoice requests --- app/Export/CSV/InvoiceExport.php | 141 ++++++++++++++++-- .../Payment/ValidInvoicesRules.php | 4 +- 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index 3069412dd692..e1c3acbbe038 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -11,28 +11,147 @@ namespace App\Export\CSV; +use App\Libraries\MultiDB; +use App\Models\Client; use App\Models\Company; -use Excel; +use App\Models\Invoice; +use App\Transformers\CreditTransformer; +use App\Utils\Ninja; +use Illuminate\Support\Facades\App; +use League\Csv\Writer; class InvoiceExport { private $company; - public function __construct(Company $company) + private $report_keys; + + private $invoice_transformer; + + private array $entity_keys = [ + 'amount' => 'amount', + 'balance' => 'balance', + 'client' => 'client_id', + 'custom_surcharge1' => 'custom_surcharge1', + 'custom_surcharge2' => 'custom_surcharge2', + 'custom_surcharge3' => 'custom_surcharge3', + 'custom_surcharge4' => 'custom_surcharge4', + 'country' => 'country_id', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'date' => 'date', + 'discount' => 'discount', + 'due_date' => 'due_date', + 'exchange_rate' => 'exchange_rate', + 'footer' => 'footer', + 'invoice' => 'invoice_id', + 'number' => 'number', + 'paid_to_date' => 'paid_to_date', + 'partial' => 'partial', + 'partial_due_date' => 'partial_due_date', + 'po_number' => 'po_number', + 'private_notes' => 'private_notes', + 'public_notes' => 'public_notes', + 'status' => 'status_id', + 'tax_name1' => 'tax_name1', + 'tax_name2' => 'tax_name2', + 'tax_name3' => 'tax_name3', + 'tax_rate1' => 'tax_rate1', + 'tax_rate2' => 'tax_rate2', + 'tax_rate3' => 'tax_rate3', + 'terms' => 'terms', + 'total_taxes' => 'total_taxes', + 'currency' => 'currency' + ]; + + private array $decorate_keys = [ + 'country', + 'client', + 'invoice', + 'currency', + ]; + + public function __construct(Company $company, array $report_keys) { $this->company = $company; + $this->report_keys = $report_keys; + $this->invoice_transformer = new CreditTransformer(); } - public function export() + public function run() { - // $fileName = 'test.csv'; - - // $data = $this->company->invoices->get(); - // return Excel::create($fileName, function ($excel) use ($data) { - // $excel->sheet('', function ($sheet) use ($data) { - // $sheet->loadView('export', $data); - // }); - // })->download('csv'); + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Invoice::with('client')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($invoice){ + + $this->csv->insertOne($this->buildRow($invoice)); + + }); + + + return $this->csv->toString(); + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(Credit $invoice) :array + { + + $transformed_invoice = $this->invoice_transformer->transform($invoice); + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $entity[$key] = $transformed_invoice[$key]; + } + + return $this->decorateAdvancedFields($invoice, $entity); + + } + + private function decorateAdvancedFields(Credit $invoice, array $entity) :array + { + + if(array_key_exists('country_id', $entity)) + $entity['country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : ""; + + if(array_key_exists('currency', $entity)) + $entity['currency'] = $invoice->client->currency()->code; + + if(array_key_exists('invoice_id', $entity)) + $entity['invoice_id'] = $invoice->invoice ? $invoice->invoice->number : ""; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $invoice->client->present()->name(); + + return $entity; + } + } diff --git a/app/Http/ValidationRules/Payment/ValidInvoicesRules.php b/app/Http/ValidationRules/Payment/ValidInvoicesRules.php index f3a333a091c7..1de6cc6bc877 100644 --- a/app/Http/ValidationRules/Payment/ValidInvoicesRules.php +++ b/app/Http/ValidationRules/Payment/ValidInvoicesRules.php @@ -81,13 +81,13 @@ class ValidInvoicesRules implements Rule if($inv->status_id == Invoice::STATUS_DRAFT && $invoice['amount'] <= $inv->amount){ //catch here nothing to do - we need this to prevent the last elseif triggering } - else if($inv->status_id == Invoice::STATUS_DRAFT && $invoice['amount'] > $inv->amount){ + else if($inv->status_id == Invoice::STATUS_DRAFT && floatval($invoice['amount']) > floatval($inv->amount)){ $this->error_msg = 'Amount cannot be greater than invoice balance'; return false; } - else if($invoice['amount'] > $inv->balance) { + else if(floatval($invoice['amount']) > floatval($inv->balance)) { $this->error_msg = ctrans('texts.amount_greater_than_balance_v5'); From 0d1deaa89d886e8dd9d9c05d16d6488382dff4b1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 14:54:59 +1000 Subject: [PATCH 08/10] Invoice / Quote exports --- app/Export/CSV/InvoiceExport.php | 20 +--- app/Export/CSV/QuoteExport.php | 151 +++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 app/Export/CSV/QuoteExport.php diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index e1c3acbbe038..4cdbf20d719f 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -15,7 +15,7 @@ use App\Libraries\MultiDB; use App\Models\Client; use App\Models\Company; use App\Models\Invoice; -use App\Transformers\CreditTransformer; +use App\Transformers\InvoiceTransformer; use App\Utils\Ninja; use Illuminate\Support\Facades\App; use League\Csv\Writer; @@ -36,7 +36,6 @@ class InvoiceExport 'custom_surcharge2' => 'custom_surcharge2', 'custom_surcharge3' => 'custom_surcharge3', 'custom_surcharge4' => 'custom_surcharge4', - 'country' => 'country_id', 'custom_value1' => 'custom_value1', 'custom_value2' => 'custom_value2', 'custom_value3' => 'custom_value3', @@ -46,7 +45,6 @@ class InvoiceExport 'due_date' => 'due_date', 'exchange_rate' => 'exchange_rate', 'footer' => 'footer', - 'invoice' => 'invoice_id', 'number' => 'number', 'paid_to_date' => 'paid_to_date', 'partial' => 'partial', @@ -63,13 +61,12 @@ class InvoiceExport 'tax_rate3' => 'tax_rate3', 'terms' => 'terms', 'total_taxes' => 'total_taxes', - 'currency' => 'currency' + 'currency' => 'client_id' ]; private array $decorate_keys = [ 'country', 'client', - 'invoice', 'currency', ]; @@ -77,7 +74,7 @@ class InvoiceExport { $this->company = $company; $this->report_keys = $report_keys; - $this->invoice_transformer = new CreditTransformer(); + $this->invoice_transformer = new InvoiceTransformer(); } public function run() @@ -120,7 +117,7 @@ class InvoiceExport return $header; } - private function buildRow(Credit $invoice) :array + private function buildRow(Invoice $invoice) :array { $transformed_invoice = $this->invoice_transformer->transform($invoice); @@ -136,18 +133,11 @@ class InvoiceExport } - private function decorateAdvancedFields(Credit $invoice, array $entity) :array + private function decorateAdvancedFields(Invoice $invoice, array $entity) :array { - - if(array_key_exists('country_id', $entity)) - $entity['country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : ""; - if(array_key_exists('currency', $entity)) $entity['currency'] = $invoice->client->currency()->code; - if(array_key_exists('invoice_id', $entity)) - $entity['invoice_id'] = $invoice->invoice ? $invoice->invoice->number : ""; - if(array_key_exists('client_id', $entity)) $entity['client_id'] = $invoice->client->present()->name(); diff --git a/app/Export/CSV/QuoteExport.php b/app/Export/CSV/QuoteExport.php new file mode 100644 index 000000000000..fbc5ff7aa4ab --- /dev/null +++ b/app/Export/CSV/QuoteExport.php @@ -0,0 +1,151 @@ + 'amount', + 'balance' => 'balance', + 'client' => 'client_id', + 'custom_surcharge1' => 'custom_surcharge1', + 'custom_surcharge2' => 'custom_surcharge2', + 'custom_surcharge3' => 'custom_surcharge3', + 'custom_surcharge4' => 'custom_surcharge4', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'date' => 'date', + 'discount' => 'discount', + 'due_date' => 'due_date', + 'exchange_rate' => 'exchange_rate', + 'footer' => 'footer', + 'number' => 'number', + 'paid_to_date' => 'paid_to_date', + 'partial' => 'partial', + 'partial_due_date' => 'partial_due_date', + 'po_number' => 'po_number', + 'private_notes' => 'private_notes', + 'public_notes' => 'public_notes', + 'status' => 'status_id', + 'tax_name1' => 'tax_name1', + 'tax_name2' => 'tax_name2', + 'tax_name3' => 'tax_name3', + 'tax_rate1' => 'tax_rate1', + 'tax_rate2' => 'tax_rate2', + 'tax_rate3' => 'tax_rate3', + 'terms' => 'terms', + 'total_taxes' => 'total_taxes', + 'currency' => 'client_id', + 'invoice' => 'invoice_id', + ]; + + private array $decorate_keys = [ + 'client', + 'currency', + 'invoice' + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->quote_transformer = new QuoteTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Quote::with('client')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($quote){ + + $this->csv->insertOne($this->buildRow($quote)); + + }); + + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(Quote $quote) :array + { + + $transformed_quote = $this->quote_transformer->transform($quote); + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $entity[$key] = $transformed_quote[$key]; + } + + return $this->decorateAdvancedFields($quote, $entity); + + } + + private function decorateAdvancedFields(Quote $quote, array $entity) :array + { + if(array_key_exists('currency', $entity)) + $entity['currency'] = $quote->client->currency()->code; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $quote->client->present()->name(); + + if(array_key_exists('invoice', $entity)) + $entity['invoice'] = $quote->invoice ? $quote->invoice->number : ""; + + return $entity; + } + +} From 7e8a72eb04b2b700ccbe9d69ad739c0f6cf61e58 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 17:03:03 +1000 Subject: [PATCH 09/10] Expense ExportP --- app/Export/CSV/ExpenseExport.php | 164 +++++++++++++++++++++++++++++++ app/Models/Expense.php | 20 ++++ 2 files changed, 184 insertions(+) create mode 100644 app/Export/CSV/ExpenseExport.php diff --git a/app/Export/CSV/ExpenseExport.php b/app/Export/CSV/ExpenseExport.php new file mode 100644 index 000000000000..4249a685839d --- /dev/null +++ b/app/Export/CSV/ExpenseExport.php @@ -0,0 +1,164 @@ + 'amount', + 'category' => 'category_id', + 'client' => 'client_id', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'currency' => 'currency_id', + 'date' => 'date', + 'exchange_rate' => 'exchange_rate', + 'converted_amount' => 'foreign_amount', + 'invoice_currency_id' => 'invoice_currency_id', + 'payment_date' => 'payment_date', + 'number' => 'number', + 'payment_type_id' => 'payment_type_id', + 'private_notes' => 'private_notes', + 'project' => 'project_id', + 'public_notes' => 'public_notes', + 'tax_amount1' => 'tax_amount1', + 'tax_amount2' => 'tax_amount2', + 'tax_amount3' => 'tax_amount3', + 'tax_name1' => 'tax_name1', + 'tax_name2' => 'tax_name2', + 'tax_name3' => 'tax_name3', + 'tax_rate1' => 'tax_rate1', + 'tax_rate2' => 'tax_rate2', + 'tax_rate3' => 'tax_rate3', + 'transaction_reference' => 'transaction_reference', + 'vendor' => 'vendor_id', + 'invoice' => 'invoice_id', + ]; + + private array $decorate_keys = [ + 'client', + 'currency', + 'invoice', + 'category', + 'vendor', + 'project', + 'payment_type_id', + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->expense_transformer = new ExpenseTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Expense::with('client')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($expense){ + + $this->csv->insertOne($this->buildRow($expense)); + + }); + + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(Expense $expense) :array + { + + $transformed_expense = $this->expense_transformer->transform($expense); + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + $entity[$key] = $transformed_expense[$key]; + } + + return $this->decorateAdvancedFields($expense, $entity); + + } + + private function decorateAdvancedFields(Expense $expense, array $entity) :array + { + if(array_key_exists('currency_id', $entity)) + $entity['currency_id'] = $expense->currency ? $expense->currency->code : ""; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $expense->client ? $expense->client->present()->name() : ""; + + if(array_key_exists('invoice_id', $entity)) + $entity['invoice_id'] = $expense->invoice ? $expense->invoice->number : ""; + + if(array_key_exists('category_id', $entity)) + $entity['category_id'] = $expense->category ? $expense->category->name : ""; + + if(array_key_exists('vendor_id', $entity)) + $entity['vendor_id'] = $expense->vendor ? $expense->vendor->name : ""; + + if(array_key_exists('payment_type_id', $entity)) + $entity['payment_type_id'] = $expense->payment_type ? $expense->payment_type->name : ""; + + if(array_key_exists('project_id', $entity)) + $entity['project_id'] = $expense->project ? $expense->project->name : ""; + + + return $entity; + } + +} diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 27f1273113d1..c730654e680a 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -106,4 +106,24 @@ class Expense extends BaseModel { return ctrans('texts.expense'); } + + public function currency() + { + return $this->belongsTo(Currency::class); + } + + public function category() + { + return $this->belongsTo(ExpenseCategory::class); + } + + public function payment_type() + { + return $this->belongsTo(PaymentType::class); + } + + public function project() + { + return $this->belongsTo(Project::class); + } } From d1052315044ac072ef36132067706d5bb0a89620 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 8 Apr 2022 18:10:14 +1000 Subject: [PATCH 10/10] Invoice Item export --- app/Export/CSV/InvoiceExport.php | 4 + app/Export/CSV/InvoiceItemExport.php | 207 +++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 app/Export/CSV/InvoiceItemExport.php diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index 4cdbf20d719f..fbb424c076fc 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -68,6 +68,7 @@ class InvoiceExport 'country', 'client', 'currency', + 'status', ]; public function __construct(Company $company, array $report_keys) @@ -141,6 +142,9 @@ class InvoiceExport if(array_key_exists('client_id', $entity)) $entity['client_id'] = $invoice->client->present()->name(); + if(array_key_exists('status_id', $entity)) + $entity['status_id'] = $invoice->stringStatus($invoice->status_id); + return $entity; } diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php new file mode 100644 index 000000000000..1f7d9ee96bef --- /dev/null +++ b/app/Export/CSV/InvoiceItemExport.php @@ -0,0 +1,207 @@ + 'amount', + 'balance' => 'balance', + 'client' => 'client_id', + 'custom_surcharge1' => 'custom_surcharge1', + 'custom_surcharge2' => 'custom_surcharge2', + 'custom_surcharge3' => 'custom_surcharge3', + 'custom_surcharge4' => 'custom_surcharge4', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'date' => 'date', + 'discount' => 'discount', + 'due_date' => 'due_date', + 'exchange_rate' => 'exchange_rate', + 'footer' => 'footer', + 'number' => 'number', + 'paid_to_date' => 'paid_to_date', + 'partial' => 'partial', + 'partial_due_date' => 'partial_due_date', + 'po_number' => 'po_number', + 'private_notes' => 'private_notes', + 'public_notes' => 'public_notes', + 'status' => 'status_id', + 'tax_name1' => 'tax_name1', + 'tax_name2' => 'tax_name2', + 'tax_name3' => 'tax_name3', + 'tax_rate1' => 'tax_rate1', + 'tax_rate2' => 'tax_rate2', + 'tax_rate3' => 'tax_rate3', + 'terms' => 'terms', + 'total_taxes' => 'total_taxes', + 'currency' => 'currency_id', + 'qty' => 'item.quantity', + 'unit_cost' => 'item.cost', + 'product_key' => 'item.product_key', + 'cost' => 'item.product_cost', + 'notes' => 'item.notes', + 'discount' => 'item.discount', + 'is_amount_discount' => 'item.is_amount_discount', + 'tax_rate1' => 'item.tax_rate1', + 'tax_rate2' => 'item.tax_rate2', + 'tax_rate3' => 'item.tax_rate3', + 'tax_name1' => 'item.tax_name1', + 'tax_name2' => 'item.tax_name2', + 'tax_name3' => 'item.tax_name3', + 'line_total' => 'item.line_total', + 'gross_line_total' => 'item.gross_line_total', + 'invoice1' => 'item.custom_value1', + 'invoice2' => 'item.custom_value2', + 'invoice3' => 'item.custom_value3', + 'invoice4' => 'item.custom_value4', + ]; + + private array $decorate_keys = [ + 'client', + 'currency', + ]; + + public function __construct(Company $company, array $report_keys) + { + $this->company = $company; + $this->report_keys = $report_keys; + $this->invoice_transformer = new InvoiceTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + Invoice::with('client')->where('company_id', $this->company->id) + ->where('is_deleted',0) + ->cursor() + ->each(function ($invoice){ + + $this->iterateItems($invoice); + + }); + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->report_keys) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function iterateItems(Invoice $invoice) + { + $transformed_invoice = $this->buildRow($invoice); + + $transformed_items = []; + + foreach($invoice->line_items as $item) + { + $item_array = []; + + foreach(array_values($this->report_keys) as $key){ + + if(str_contains($key, "item.")){ + + $key = str_replace("item.", "", $key); + $item_array[$key] = $item->{$key}; + } + + } + + $entity = []; + + $transformed_items = array_merge($transformed_invoice, $item_array); + + $transformed_items = $this->decorateAdvancedFields($invoice, $transformed_items); + + foreach(array_values($this->report_keys) as $key) + { + $key = str_replace("item.", "", $key); + $entity[$key] = $transformed_items[$key]; + } + + $this->csv->insertOne($entity); + + } + + } + + private function buildRow(Invoice $invoice) :array + { + + $transformed_invoice = $this->invoice_transformer->transform($invoice); + + $entity = []; + + foreach(array_values($this->report_keys) as $key){ + + if(!str_contains($key, "item.")) + $entity[$key] = $transformed_invoice[$key]; + + } + + return $this->decorateAdvancedFields($invoice, $entity); + + } + + private function decorateAdvancedFields(Invoice $invoice, array $entity) :array + { + if(array_key_exists('currency_id', $entity)) + $entity['currency_id'] = $invoice->client->currency()->code; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $invoice->client->present()->name(); + + if(array_key_exists('status_id', $entity)) + $entity['status_id'] = $invoice->stringStatus($invoice->status_id); + + return $entity; + } + +}