From d45571d7f9d68e6fa6f82371b846098054070a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 9 Dec 2020 15:17:48 +0100 Subject: [PATCH 01/87] wip --- .../ClientPortal/PaymentController.php | 1 + app/Models/Client.php | 1 + app/PaymentDrivers/BaseDriver.php | 5 + app/PaymentDrivers/CustomPaymentDriver.php | 45 ++++-- resources/lang/en/texts.php | 2 + .../checkout/credit_card.blade.php.old | 128 ------------------ .../gateways/custom/landing_page.blade.php | 1 - .../gateways/custom/payment.blade.php | 33 +++++ 8 files changed, 73 insertions(+), 143 deletions(-) delete mode 100644 resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php.old delete mode 100644 resources/views/portal/ninja2020/gateways/custom/landing_page.blade.php create mode 100644 resources/views/portal/ninja2020/gateways/custom/payment.blade.php diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 61cdc83456be..b3bbf2a94bcb 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -232,6 +232,7 @@ class PaymentController extends Controller public function response(PaymentResponseRequest $request) { $gateway = CompanyGateway::find($request->input('company_gateway_id'))->firstOrFail(); + $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->payment_hash])->first(); return $gateway diff --git a/app/Models/Client.php b/app/Models/Client.php index 922beefd2098..7c0d648756de 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -462,6 +462,7 @@ class Client extends BaseModel implements HasLocalePreference $payment_methods = []; foreach ($gateways as $gateway) { + foreach ($gateway->driver($this)->gatewayTypes() as $type) { if (isset($gateway->fees_and_limits) && property_exists($gateway->fees_and_limits, $type)) { if ($this->validGatewayForAmount($gateway->fees_and_limits->{$type}, $amount)) { diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 7e097c704b53..4d4b017beecf 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -460,4 +460,9 @@ class BaseDriver extends AbstractPaymentDriver return $this; } + + public function getCompanyGatewayId(): int + { + return $this->company_gateway->id; + } } diff --git a/app/PaymentDrivers/CustomPaymentDriver.php b/app/PaymentDrivers/CustomPaymentDriver.php index 03c76eb7007f..492ecfe66e51 100644 --- a/app/PaymentDrivers/CustomPaymentDriver.php +++ b/app/PaymentDrivers/CustomPaymentDriver.php @@ -12,9 +12,12 @@ namespace App\PaymentDrivers; +use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; use App\Models\GatewayType; use App\Models\Payment; +use App\Models\PaymentType; +use App\Models\SystemLog; /** * Class CustomPaymentDriver. @@ -28,7 +31,7 @@ class CustomPaymentDriver extends BaseDriver /** * Returns the gateway types. */ - public function gatewayTypes() :array + public function gatewayTypes(): array { $types = [ GatewayType::CREDIT_CARD, @@ -37,18 +40,6 @@ class CustomPaymentDriver extends BaseDriver return $types; } - public function authorize($payment_method) - { - } - - public function purchase($amount, $return_client_response = false) - { - } - - public function refund(Payment $payment, $amount, $return_client_response = false) - { - } - public function setPaymentMethod($payment_method_id) { $this->payment_method = $payment_method_id; @@ -58,11 +49,37 @@ class CustomPaymentDriver extends BaseDriver public function processPaymentView($data) { - return render('gateways.custom.landing_page', $data); + $data['title'] = $this->company_gateway->getConfigField('name'); + $data['instructions'] = $this->company_gateway->getConfigField('text'); + + $this->payment_hash->data = array_merge((array) $this->payment_hash->data, $data); + $this->payment_hash->save(); + + $data['gateway'] = $this; + + return render('gateways.custom.payment', $data); } public function processPaymentResponse($request) { + $data = [ + 'payment_method' => GatewayType::CREDIT_CARD, + 'payment_type' => PaymentType::CREDIT_CARD_OTHER, + 'amount' => $this->payment_hash->data->amount_with_fee, + 'transaction_reference' => \Illuminate\Support\Str::uuid(), + ]; + + $payment = $this->createPayment($data, Payment::STATUS_PENDING); + + SystemLogger::dispatch( + ['response' => $data, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_STRIPE, + $this->client, + ); + + return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); } /** diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 6538ce145461..e0fbc8dfca9f 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3314,4 +3314,6 @@ return [ 'service' => 'Service', 'pay' => 'Pay', + + 'instructions' => 'Instructions', ]; diff --git a/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php.old b/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php.old deleted file mode 100644 index 71f54319f938..000000000000 --- a/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php.old +++ /dev/null @@ -1,128 +0,0 @@ -@extends('portal.ninja2020.layout.app') -@section('meta_title', ctrans('texts.checkout_com')) - -@push('head') - - - - - - - -@endpush - -@section('body') -
- @csrf - - - - - - - - - - @isset($token) - - @endisset -
- -
-
-
- -
-
-

- {{ ctrans('texts.pay_now') }} -

-

- {{ ctrans('texts.complete_your_payment') }} -

-
-
-
- {{ ctrans('texts.payment_type') }} -
-
- {{ ctrans('texts.checkout_com') }} ({{ ctrans('texts.credit_card') }}) -
-
-
-
- {{ ctrans('texts.subtotal') }} -
-
- {{ App\Utils\Number::formatMoney($total['invoice_totals'], $client) }} -
-
- {{ ctrans('texts.gateway_fees') }} -
-
- {{ App\Utils\Number::formatMoney($total['fee_total'], $client) }} -
-
- {{ ctrans('texts.amount') }} -
-
- {{ App\Utils\Number::formatMoney($total['amount_with_fee'], $client) }} -
-
- @isset($token) -
-
- {{ ctrans('texts.card_number') }} -
-
- **** {{ ucfirst($token->meta->last4) }} -
-
-
- -
- @else -
-
- {{ ctrans('texts.token_billing_checkbox') }} -
-
- - -
-
-
-
- @if(app()->environment() == 'production') - - @else - - @endif -
-
- @endisset -
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/portal/ninja2020/gateways/custom/landing_page.blade.php b/resources/views/portal/ninja2020/gateways/custom/landing_page.blade.php deleted file mode 100644 index 5129524a8bee..000000000000 --- a/resources/views/portal/ninja2020/gateways/custom/landing_page.blade.php +++ /dev/null @@ -1 +0,0 @@ -stubs \ No newline at end of file diff --git a/resources/views/portal/ninja2020/gateways/custom/payment.blade.php b/resources/views/portal/ninja2020/gateways/custom/payment.blade.php new file mode 100644 index 000000000000..7d3069f8bea6 --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/custom/payment.blade.php @@ -0,0 +1,33 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => $title, 'card_title' => $title]) + +@section('gateway_content') +
+ @csrf + + + +
+ + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')]) + {{ $title }} + @endcomponent + + @include('portal.ninja2020.gateways.includes.payment_details') + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.instructions') ]) + {!! nl2br($instructions) !!} + @endcomponent + + @component('portal.ninja2020.components.general.card-element-single') + @include('portal.ninja2020.gateways.includes.pay_now') + @endcomponent +@endsection + +@section('gateway_footer') + +@endsection + From 37f79247aca6223829a5b6e7acd5e77272bca60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 10 Dec 2020 12:19:13 +0100 Subject: [PATCH 02/87] remove payment options from custom driver --- .../gateways/custom/payment.blade.php | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/resources/views/portal/ninja2020/gateways/custom/payment.blade.php b/resources/views/portal/ninja2020/gateways/custom/payment.blade.php index 7d3069f8bea6..d337c71897d9 100644 --- a/resources/views/portal/ninja2020/gateways/custom/payment.blade.php +++ b/resources/views/portal/ninja2020/gateways/custom/payment.blade.php @@ -1,33 +1,13 @@ @extends('portal.ninja2020.layout.payments', ['gateway_title' => $title, 'card_title' => $title]) @section('gateway_content') -
- @csrf - - - -
- @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')]) {{ $title }} @endcomponent @include('portal.ninja2020.gateways.includes.payment_details') - @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.instructions') ]) + @component('portal.ninja2020.components.general.card-element-single') {!! nl2br($instructions) !!} @endcomponent - - @component('portal.ninja2020.components.general.card-element-single') - @include('portal.ninja2020.gateways.includes.pay_now') - @endcomponent @endsection - -@section('gateway_footer') - -@endsection - From 5c776d4911cb7f2da6a176249b1a7940524e03fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 10 Dec 2020 12:38:07 +0100 Subject: [PATCH 03/87] show custom driver with its label --- .../portal/ninja2020/invoices/payment.blade.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/resources/views/portal/ninja2020/invoices/payment.blade.php b/resources/views/portal/ninja2020/invoices/payment.blade.php index 66ecc2a0ece5..f911440f30ed 100644 --- a/resources/views/portal/ninja2020/invoices/payment.blade.php +++ b/resources/views/portal/ninja2020/invoices/payment.blade.php @@ -36,9 +36,15 @@ @@ -67,7 +73,7 @@
@if(!empty($invoice->number) && !is_null($invoice->number)) -
+
{{ ctrans('texts.invoice_number') }}
@@ -88,7 +94,7 @@
@endif -
+
{{ ctrans('texts.additional_info') }}
From 9df493883762cba27b8e7951ba8ee78630cc4c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 10 Dec 2020 12:38:23 +0100 Subject: [PATCH 04/87] change gateway type & remove processPayment --- app/PaymentDrivers/CustomPaymentDriver.php | 32 +++++++++------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/app/PaymentDrivers/CustomPaymentDriver.php b/app/PaymentDrivers/CustomPaymentDriver.php index 492ecfe66e51..00e111ba4105 100644 --- a/app/PaymentDrivers/CustomPaymentDriver.php +++ b/app/PaymentDrivers/CustomPaymentDriver.php @@ -34,7 +34,7 @@ class CustomPaymentDriver extends BaseDriver public function gatewayTypes(): array { $types = [ - GatewayType::CREDIT_CARD, + GatewayType::CUSTOM, ]; return $types; @@ -47,6 +47,12 @@ class CustomPaymentDriver extends BaseDriver return $this; } + /** + * View for displaying custom content of the driver. + * + * @param array $data + * @return mixed + */ public function processPaymentView($data) { $data['title'] = $this->company_gateway->getConfigField('name'); @@ -60,26 +66,14 @@ class CustomPaymentDriver extends BaseDriver return render('gateways.custom.payment', $data); } + /** + * Processing method for payment. Should never be reached with this driver. + * + * @return mixed + */ public function processPaymentResponse($request) { - $data = [ - 'payment_method' => GatewayType::CREDIT_CARD, - 'payment_type' => PaymentType::CREDIT_CARD_OTHER, - 'amount' => $this->payment_hash->data->amount_with_fee, - 'transaction_reference' => \Illuminate\Support\Str::uuid(), - ]; - - $payment = $this->createPayment($data, Payment::STATUS_PENDING); - - SystemLogger::dispatch( - ['response' => $data, 'data' => $data], - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_SUCCESS, - SystemLog::TYPE_STRIPE, - $this->client, - ); - - return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); + return redirect()->route('client.invoices'); } /** From 5f796aeab6a26d674962136f765a109dec678094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 10 Dec 2020 12:38:46 +0100 Subject: [PATCH 05/87] php-cs-fixer --- app/Models/Client.php | 1 - app/PaymentDrivers/CustomPaymentDriver.php | 13 +++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/Models/Client.php b/app/Models/Client.php index 7c0d648756de..922beefd2098 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -462,7 +462,6 @@ class Client extends BaseModel implements HasLocalePreference $payment_methods = []; foreach ($gateways as $gateway) { - foreach ($gateway->driver($this)->gatewayTypes() as $type) { if (isset($gateway->fees_and_limits) && property_exists($gateway->fees_and_limits, $type)) { if ($this->validGatewayForAmount($gateway->fees_and_limits->{$type}, $amount)) { diff --git a/app/PaymentDrivers/CustomPaymentDriver.php b/app/PaymentDrivers/CustomPaymentDriver.php index 00e111ba4105..3c5d4bad1967 100644 --- a/app/PaymentDrivers/CustomPaymentDriver.php +++ b/app/PaymentDrivers/CustomPaymentDriver.php @@ -12,12 +12,9 @@ namespace App\PaymentDrivers; -use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; use App\Models\GatewayType; use App\Models\Payment; -use App\Models\PaymentType; -use App\Models\SystemLog; /** * Class CustomPaymentDriver. @@ -49,9 +46,9 @@ class CustomPaymentDriver extends BaseDriver /** * View for displaying custom content of the driver. - * - * @param array $data - * @return mixed + * + * @param array $data + * @return mixed */ public function processPaymentView($data) { @@ -68,8 +65,8 @@ class CustomPaymentDriver extends BaseDriver /** * Processing method for payment. Should never be reached with this driver. - * - * @return mixed + * + * @return mixed */ public function processPaymentResponse($request) { From f6ed7be0da372b44e2718cb5272f3a08bd9a380c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Dec 2020 07:51:10 +1100 Subject: [PATCH 06/87] Fixes for expense and project numbers --- app/Http/Controllers/PreviewController.php | 3 +++ app/Http/Requests/Expense/StoreExpenseRequest.php | 13 +++++++++---- app/Http/Requests/Project/StoreProjectRequest.php | 6 +++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index 155d961a247c..d81d98629faf 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -122,6 +122,9 @@ class PreviewController extends BaseController ->design($design) ->build(); + if(request()->has('html') && request()->input('html') == true) + return $maker->getCompiledHTML; + //if phantom js...... inject here.. if (config('ninja.phantomjs_pdf_generation')) { return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true)); diff --git a/app/Http/Requests/Expense/StoreExpenseRequest.php b/app/Http/Requests/Expense/StoreExpenseRequest.php index 555ed82ea014..e2b5aa3ff2ee 100644 --- a/app/Http/Requests/Expense/StoreExpenseRequest.php +++ b/app/Http/Requests/Expense/StoreExpenseRequest.php @@ -35,9 +35,12 @@ class StoreExpenseRequest extends Request { $rules = []; - $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id); + if (isset($this->number)) { + $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id); + } + // $rules['number'] = 'unique:expenses,number,'.$this->id.',id,company_id,'.auth()->user()->company()->id; - $rules['contacts.*.email'] = 'nullable|distinct'; + // $rules['contacts.*.email'] = 'nullable|distinct'; //$rules['number'] = new UniqueExpenseNumberRule($this->all()); $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; @@ -55,6 +58,10 @@ class StoreExpenseRequest extends Request $input['category_id'] = $this->decodePrimaryKey($input['category_id']); } + if (! array_key_exists('currency_id', $input)) { + $input['currency_id'] = auth()->user()->company()->settings->currency_id; + } + $this->replace($input); } @@ -62,8 +69,6 @@ class StoreExpenseRequest extends Request { return [ 'unique' => ctrans('validation.unique', ['attribute' => 'email']), - //'required' => trans('validation.required', ['attribute' => 'email']), - 'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']), ]; } } diff --git a/app/Http/Requests/Project/StoreProjectRequest.php b/app/Http/Requests/Project/StoreProjectRequest.php index a7f77e9d2c67..ec50b314c70e 100644 --- a/app/Http/Requests/Project/StoreProjectRequest.php +++ b/app/Http/Requests/Project/StoreProjectRequest.php @@ -15,6 +15,7 @@ use App\Http\Requests\Request; use App\Models\Client; use App\Models\Project; use App\Utils\Traits\MakesHash; +use Illuminate\Validation\Rule; class StoreProjectRequest extends Request { @@ -36,7 +37,10 @@ class StoreProjectRequest extends Request $rules['name'] = 'required'; $rules['client_id'] = 'required|exists:clients,id,company_id,'.auth()->user()->company()->id; - $rules['number'] = 'unique:projects,number,'.$this->id.',id,company_id,'.auth()->user()->company()->id; + + if (isset($this->number)) { + $rules['number'] = Rule::unique('projects')->where('company_id', auth()->user()->company()->id); + } return $this->globalRules($rules); } From aa1a788d6e347148eec7e205ad45be1e2aa925bc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Dec 2020 19:46:28 +1100 Subject: [PATCH 07/87] Public document download route --- app/Console/Commands/DemoMode.php | 76 ++++++++++++++----- .../ClientPortal/DocumentController.php | 12 +++ routes/client.php | 1 + 3 files changed, 71 insertions(+), 18 deletions(-) diff --git a/app/Console/Commands/DemoMode.php b/app/Console/Commands/DemoMode.php index d5b9a437e615..b80c6c5fd138 100644 --- a/app/Console/Commands/DemoMode.php +++ b/app/Console/Commands/DemoMode.php @@ -15,6 +15,7 @@ use App\DataMapper\CompanySettings; use App\Events\Invoice\InvoiceWasCreated; use App\Factory\InvoiceFactory; use App\Factory\InvoiceItemFactory; +use App\Factory\RecurringInvoiceFactory; use App\Helpers\Invoice\InvoiceSum; use App\Jobs\Company\CreateCompanyPaymentTerms; use App\Jobs\Company\CreateCompanyTaskStatuses; @@ -30,6 +31,7 @@ use App\Models\Expense; use App\Models\Product; use App\Models\Project; use App\Models\Quote; +use App\Models\RecurringInvoice; use App\Models\Task; use App\Models\User; use App\Models\Vendor; @@ -238,43 +240,26 @@ class DemoMode extends Command $this->info('creating entities for client #'.$client->id); $this->createInvoice($client, $u2->id); - // for($y=0; $y<($this->count); $y++){ - // $this->info("creating invoice #{$y} for client #".$client->id); - // } + $this->createRecurringInvoice($client, $u2->id); $client = $company->clients->random(); $this->createCredit($client, $u2->id); - // for($y=0; $y<($this->count); $y++){ - // $this->info("creating credit #{$y} for client #".$client->id); - // } - $client = $company->clients->random(); $this->createQuote($client, $u2->id); - // for($y=0; $y<($this->count); $y++){ - // $this->info("creating quote #{$y} for client #".$client->id); - // } - $client = $company->clients->random(); $this->createExpense($client); - //$this->info("creating expense for client #".$client->id); - $client = $company->clients->random(); $this->createVendor($client, $u2->id); - // $this->info("creating vendor for client #".$client->id); - $client = $company->clients->random(); $this->createTask($client, $u2->id); - // $this->info("creating task for client #".$client->id); - $client = $company->clients->random(); $this->createProject($client, $u2->id); - // $this->info("creating project for client #".$client->id); } } @@ -352,6 +337,7 @@ class DemoMode extends Command $vendor = Task::factory()->create([ 'user_id' => $client->user->id, 'company_id' => $client->company_id, + 'client_id' => $client->id ]); } @@ -431,6 +417,60 @@ class DemoMode extends Command event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars())); } + private function createRecurringInvoice($client, $assigned_user_id = null) + { + $faker = \Faker\Factory::create(); + + $invoice = RecurringInvoiceFactory::create($client->company->id, $client->user->id); //stub the company and user_id + $invoice->client_id = $client->id; + $invoice->frequency_id = RecurringInvoice::FREQUENCY_MONTHLY; + $invoice->last_sent_date = now()->subMonth(); + $invoice->next_send_date = now()->addMonthNoOverflow(); + + if ((bool) rand(0, 1)) { + $dateable = Carbon::now()->subDays(rand(0, 90)); + } else { + $dateable = Carbon::now()->addDays(rand(0, 90)); + } + + $invoice->date = $dateable; + + $invoice->line_items = $this->buildLineItems(rand(1, 10)); + $invoice->uses_inclusive_taxes = false; + + if (rand(0, 1)) { + $invoice->tax_name1 = 'GST'; + $invoice->tax_rate1 = 10.00; + } + + if (rand(0, 1)) { + $invoice->tax_name2 = 'VAT'; + $invoice->tax_rate2 = 17.50; + } + + if (rand(0, 1)) { + $invoice->tax_name3 = 'CA Sales Tax'; + $invoice->tax_rate3 = 5; + } + + // $invoice->custom_value1 = $faker->date; + // $invoice->custom_value2 = rand(0, 1) ? 'yes' : 'no'; + + $invoice->save(); + + $invoice_calc = new InvoiceSum($invoice); + $invoice_calc->build(); + + $invoice = $invoice_calc->getInvoice(); + + if (rand(0, 1)) { + $invoice->assigned_user_id = $assigned_user_id; + } + + $invoice->save(); + + } + private function createCredit($client, $assigned_user_id = null) { $faker = \Faker\Factory::create(); diff --git a/app/Http/Controllers/ClientPortal/DocumentController.php b/app/Http/Controllers/ClientPortal/DocumentController.php index cd4489454409..be7332e4d33d 100644 --- a/app/Http/Controllers/ClientPortal/DocumentController.php +++ b/app/Http/Controllers/ClientPortal/DocumentController.php @@ -15,6 +15,7 @@ namespace App\Http\Controllers\ClientPortal; use App\Http\Controllers\Controller; use App\Http\Requests\ClientPortal\Documents\ShowDocumentRequest; use App\Http\Requests\Document\DownloadMultipleDocumentsRequest; +use App\Models\ClientContact; use App\Models\Document; use App\Utils\TempFile; use App\Utils\Traits\MakesHash; @@ -53,6 +54,17 @@ class DocumentController extends Controller return Storage::disk($document->disk)->download($document->url, $document->name); } + public function publicDownload(string $contact_key, Document $document) + { + //return failure if the contact is not associated with the document + $contact = ClientContact::where('contact_key', $contact_key)->firstOrFail(); + + if($contact->company_id == $document->company_id) + return Storage::disk($document->disk)->download($document->url, $document->name); + + return response()->json(['message' => 'Access denied']); + } + public function downloadMultiple(DownloadMultipleDocumentsRequest $request) { $documents = Document::whereIn('id', $this->transformKeys($request->file_hash)) diff --git a/routes/client.php b/routes/client.php index 46075c5e334a..b78370876d23 100644 --- a/routes/client.php +++ b/routes/client.php @@ -22,6 +22,7 @@ Route::post('view/{entity_type}/{invitation_key}/password', 'ClientPortal\Entity Route::get('tmp_pdf/{hash}', 'ClientPortal\TempRouteController@index')->name('tmp_pdf'); Route::get('client/key_login/{contact_key}', 'ClientPortal\ContactHashLoginController@login')->name('client.contact_login')->middleware(['contact_key_login']); +Route::get('documents/{contact_key}/{document}/download', 'ClientPortal\DocumentController@publicDownload')->name('documents.public_download'); //todo implement domain DB Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () { From 584bef52fcb473836616ece1bafad349b7cac334 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Dec 2020 21:01:53 +1100 Subject: [PATCH 08/87] Working on import --- app/Http/Controllers/ImportController.php | 102 ++++ app/Http/Requests/Import/PreImportRequest.php | 37 ++ app/Jobs/Util/UploadAvatar.php | 9 +- composer.json | 1 + composer.lock | 86 ++- routes/api.php | 2 + tests/Feature/Import/ImportCsvTest.php | 84 +++ tests/Feature/Import/invoice.csv | 512 ++++++++++++++++++ 8 files changed, 825 insertions(+), 8 deletions(-) create mode 100644 app/Http/Controllers/ImportController.php create mode 100644 app/Http/Requests/Import/PreImportRequest.php create mode 100644 tests/Feature/Import/ImportCsvTest.php create mode 100644 tests/Feature/Import/invoice.csv diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php new file mode 100644 index 000000000000..71d265a50c84 --- /dev/null +++ b/app/Http/Controllers/ImportController.php @@ -0,0 +1,102 @@ +file('file')->getPathname())), 10); + + //parse CSV + $csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname())); + } + + + private function getCsvData($csvfile) + { + + if (! ini_get('auto_detect_line_endings')) { + ini_set('auto_detect_line_endings', '1'); + } + + $csv = Reader::createFromString($csvfile); + //$csv->setHeaderOffset(0); //set the CSV header offset + $stmt = new Statement(); + $data = iterator_to_array($stmt->process($csv)); + + if (count($data) > 0) { + $headers = $data[0]; + + // Remove Invoice Ninja headers + if (count($headers) && count($data) > 4) { + $firstCell = $headers[0]; + if (strstr($firstCell, config('ninja.app_name'))) { + array_shift($data); // Invoice Ninja... + array_shift($data); // + array_shift($data); // Enitty Type Header + } + } + } + + return $data; + } +} diff --git a/app/Http/Requests/Import/PreImportRequest.php b/app/Http/Requests/Import/PreImportRequest.php new file mode 100644 index 000000000000..b62acc2ab043 --- /dev/null +++ b/app/Http/Requests/Import/PreImportRequest.php @@ -0,0 +1,37 @@ +user()->isAdmin(); + } + + public function rules() + { + + return [ + 'file' => 'required|mimes:csv' + ]; + + } +} diff --git a/app/Jobs/Util/UploadAvatar.php b/app/Jobs/Util/UploadAvatar.php index ff8700c016f2..93474a04006a 100644 --- a/app/Jobs/Util/UploadAvatar.php +++ b/app/Jobs/Util/UploadAvatar.php @@ -36,11 +36,6 @@ class UploadAvatar implements ShouldQueue public function handle() : ?string { - //make dir - // info("avatar dir creation => ". $this->directory); - - // Storage::makeDirectory($this->directory, 0775); - $tmp_file = sha1(time()).'.png'; $im = imagecreatefromstring(file_get_contents($this->file)); @@ -50,8 +45,8 @@ class UploadAvatar implements ShouldQueue $path = Storage::putFile($this->directory, new File(sys_get_temp_dir().'/'.$tmp_file)); - info($path); - info($tmp_file); + // info($path); + // info($tmp_file); $url = Storage::url($path); diff --git a/composer.json b/composer.json index 7d2b605566e7..852cc0ceb6e5 100644 --- a/composer.json +++ b/composer.json @@ -47,6 +47,7 @@ "laravel/socialite": "^5", "laravel/tinker": "^2.0", "laravel/ui": "^3.0", + "league/csv": "^9.6", "league/flysystem-aws-s3-v3": "~1.0", "league/flysystem-cached-adapter": "^1.1", "league/fractal": "^0.17.0", diff --git a/composer.lock b/composer.lock index d171da2e3278..a710907da364 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0590d36f1ac1287db12b2b3d33750866", + "content-hash": "35318cb6b03b84487f53dc09f2262030", "packages": [ { "name": "asgrim/ofxparser", @@ -3193,6 +3193,90 @@ ], "time": "2020-10-31T13:49:32+00:00" }, + { + "name": "league/csv", + "version": "9.6.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/csv.git", + "reference": "f28da6e483bf979bac10e2add384c90ae9983e4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/f28da6e483bf979bac10e2add384c90ae9983e4e", + "reference": "f28da6e483bf979bac10e2add384c90ae9983e4e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.2.5" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan-phpunit": "^0.12.0", + "phpstan/phpstan-strict-rules": "^0.12.0", + "phpunit/phpunit": "^8.5" + }, + "suggest": { + "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Csv\\": "src" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://github.com/nyamsprod/", + "role": "Developer" + } + ], + "description": "CSV data manipulation made easy in PHP", + "homepage": "http://csv.thephpleague.com", + "keywords": [ + "convert", + "csv", + "export", + "filter", + "import", + "read", + "transform", + "write" + ], + "support": { + "docs": "https://csv.thephpleague.com", + "issues": "https://github.com/thephpleague/csv/issues", + "rss": "https://github.com/thephpleague/csv/releases.atom", + "source": "https://github.com/thephpleague/csv" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2020-12-10T19:40:30+00:00" + }, { "name": "league/flysystem", "version": "1.1.3", diff --git a/routes/api.php b/routes/api.php index 81d65c713f87..85376b4e6e29 100644 --- a/routes/api.php +++ b/routes/api.php @@ -168,6 +168,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a /*Company Ledger */ Route::get('company_ledger', 'CompanyLedgerController@index')->name('company_ledger.index'); + Route::post('preimport', 'ImportController@preimport')->name('import.preimport'); + /* Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit diff --git a/tests/Feature/Import/ImportCsvTest.php b/tests/Feature/Import/ImportCsvTest.php new file mode 100644 index 000000000000..b17c53684d30 --- /dev/null +++ b/tests/Feature/Import/ImportCsvTest.php @@ -0,0 +1,84 @@ +withoutMiddleware( + ThrottleRequests::class + ); + + $this->faker = \Faker\Factory::create(); + + + $this->makeTestData(); + + $this->withoutExceptionHandling(); + } + + public function testCsvRead() + { + $csv = file_get_contents(base_path().'/tests/Feature/Import/invoice.csv'); + + return $this->getCsvData($csv); + } + + + private function getCsvData($csvfile) + { + + if (! ini_get('auto_detect_line_endings')) { + ini_set('auto_detect_line_endings', '1'); + } + + $csv = Reader::createFromString($csvfile); + //$csv->setHeaderOffset(0); //set the CSV header offset + $stmt = new Statement(); + $data = iterator_to_array($stmt->process($csv)); + + if (count($data) > 0) { + $headers = $data[0]; + + // Remove Invoice Ninja headers + if (count($headers) && count($data) > 4) { + $firstCell = $headers[0]; + if (strstr($firstCell, config('ninja.app_name'))) { + array_shift($data); // Invoice Ninja... + array_shift($data); // + array_shift($data); // Enitty Type Header + } + } + } +info(print_r($data,1)); + return $data; + } +} \ No newline at end of file diff --git a/tests/Feature/Import/invoice.csv b/tests/Feature/Import/invoice.csv new file mode 100644 index 000000000000..b945ff361740 --- /dev/null +++ b/tests/Feature/Import/invoice.csv @@ -0,0 +1,512 @@ +"Invoice Ninja v4.5.17 - 11/Dec/2020 11:50 pm","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"INVOICES","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"Client","Email","User","Invoice Number","Amount","Paid","PO Number","Status","Invoice Date","Due Date","Discount","Partial/Deposit","Partial Due Date","Public Notes","Private Notes","surcharge Label","tax tax","crv","ody","Item Product","Item Notes","prod1","prod2","Item Cost","Item Quantity","Item Tax Name","Item Tax Rate","Item Tax Name","Item Tax Rate" +"Test","g@gmail.com","David Bomba","0001","$10.00","$10.00","","Archived","2016-02-01","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0002","$11.11","$0.00","","Archived","2016-06-07","0000-00-00","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0002","$11.11","$0.00","","Archived","2016-06-07","0000-00-00","","$0.00","","","","0","0","","","123","456","","","1","1","","0","","0" +"Test","g@gmail.com","David Bomba","0002","$11.11","$0.00","","Archived","2016-06-07","0000-00-00","","$0.00","","","","0","0","","","Surcharge","Online Payment Surcharge","","","0.11","1","","0","","0" +"Test","g@gmail.com","David Bomba","0004","$10.00","$0.00","","Archived","2016-06-09","2017-01-28","","$0.00","","","","0","0","","","123","345","","","10","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0007","€10,00","€10,00","","Archived","2016-08-07","2017-01-15","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0011","€10,00","€10,00","","Archived","2016-08-13","0000-00-00","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0013","€21,00","€0,00","","Archived","2016-08-13","2017-01-17","","€0,00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0013","€21,00","€0,00","","Archived","2016-08-13","2017-01-17","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0013","€21,00","€0,00","","Archived","2016-08-13","2017-01-17","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0014","€53,00","€53,00","","Archived","2016-08-13","","","€0,00","","","","0","0","","","Hello","A description","","","10","1.5","","0","","0" +"SumFin","tu@gm.com","David Bomba","0014","€53,00","€53,00","","Archived","2016-08-13","","","€0,00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0014","€53,00","€53,00","","Archived","2016-08-13","","","€0,00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"SumFin","tu@gm.com","David Bomba","0014","€53,00","€53,00","","Archived","2016-08-13","","","€0,00","","","","0","0","","","Save","Grace","","","36","1","","0","","0" +"Test","g@gmail.com","David Bomba","0017","$22.00","$0.00","Op number","Archived","2016-08-13","2016-11-11","","$0.00","","","","0","0","","","A New Product","A New Product","","","1","2","","0","","0" +"Test","g@gmail.com","David Bomba","0017","$22.00","$0.00","Op number","Archived","2016-08-13","2016-11-11","","$0.00","","","","0","0","","","Easy","Sunday","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0017","$22.00","$0.00","Op number","Archived","2016-08-13","2016-11-11","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0018","€62,00","€0,00","","Archived","2016-08-13","0000-00-00","","€0,00","","","","0","0","","","Save","Grace","","","36","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0018","€62,00","€0,00","","Archived","2016-08-13","0000-00-00","","€0,00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0018","€62,00","€0,00","","Archived","2016-08-13","0000-00-00","","€0,00","","","","0","0","","","Hidden","Costs","","","25","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0022","€2.871,00","€0,00","","Archived","2016-08-15","0000-00-00","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0022","€2.871,00","€0,00","","Archived","2016-08-15","0000-00-00","","€0,00","","","","0","0","","","Hidden","Costs","","","25","114","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0022","€2.871,00","€0,00","","Archived","2016-08-15","0000-00-00","","€0,00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0022","€2.871,00","€0,00","","Archived","2016-08-15","0000-00-00","","€0,00","","","","0","0","","","Humpty","Green Men","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0032","€55,00","€55,00","","Archived","2016-10-09","2016-10-14","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0032","€55,00","€55,00","","Archived","2016-10-09","2016-10-14","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0032","€55,00","€55,00","","Archived","2016-10-09","2016-10-14","","€0,00","","","","0","0","","","Hidden","Costs","","","25","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0032","€55,00","€55,00","","Archived","2016-10-09","2016-10-14","","€0,00","","","","0","0","","","Humpty","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0037","$11.00","$0.00","","Archived","2016-11-15","2016-11-09","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0037","$11.00","$0.00","","Archived","2016-11-15","2016-11-09","","$0.00","","","","0","0","","","Doggie","Doggy dog style","","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0039","$120.00","$0.00","","Archived","2016-12-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0039","$120.00","$0.00","","Archived","2016-12-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0039","$120.00","$0.00","","Archived","2016-12-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0040","$10.00","$0.00","","Archived","2016-12-30","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0041","$9.00","$0.00","","Archived","2016-12-30","2017-01-13","","$0.00","","","","0","0","","","1","Third Desc","","","3","3","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0042","$120.00","$0.00","","Archived","2017-01-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0042","$120.00","$0.00","","Archived","2017-01-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0042","$120.00","$0.00","","Archived","2017-01-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"Fixxy","specialk@gmail.com.au","David Bomba","0044","€14,00","€0,00","","Archived","2017-01-14","0000-00-00","","€0,00","","","","0","0","","","1","Third Desc","","","3","1","","0","","0" +"Fixxy","specialk@gmail.com.au","David Bomba","0044","€14,00","€0,00","","Archived","2017-01-14","0000-00-00","","€0,00","","","","0","0","","","10","Green Men","","","10","1","GST","10","","0" +"Fixxy","specialk@gmail.com.au","David Bomba","0045","€14,00","€0,00","","Archived","2017-01-14","0000-00-00","","€0,00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"Fixxy","specialk@gmail.com.au","David Bomba","0045","€14,00","€0,00","","Archived","2017-01-14","0000-00-00","","€0,00","","","","0","0","","","10","Green Men","","","10","1","GST","10","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0046","$10.00","$0.00","","Archived","2017-01-30","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Craig Work","","David Bomba","0047","€3,00","€0,00","","Archived","2017-01-31","","","€0,00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0049","$1.00","$0.00","","Archived","2017-02-01","0000-00-00","","$0.00","","","","0","0","","","Doggie","Doggy dog style","","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0050","$133.00","$0.00","","Archived","2017-02-01","0000-00-00","","$0.00","","","","0","0","","","Doggie","Doggy dog style","","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0050","$133.00","$0.00","","Archived","2017-02-01","0000-00-00","","$0.00","","","","0","0","","","A New Product","A New Product","","","11","12","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0051","$120.00","$0.00","","Archived","2017-02-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0051","$120.00","$0.00","","Archived","2017-02-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0051","$120.00","$0.00","","Archived","2017-02-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"Test","g@gmail.com","David Bomba","0056","$11.00","$0.00","","Archived","2017-02-06","","","$0.00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"Test","g@gmail.com","David Bomba","0056","$11.00","$0.00","","Archived","2017-02-06","","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0057","$10.00","$0.00","","Archived","2017-02-06","","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"Fixxy","specialk@gmail.com.au","David Bomba","0060","€110,00","€0,00","","Archived","2017-02-07","","","€0,00","","","","0","0","","","asd","SMackeroo","","","100","1","","0","","0" +"Fixxy","specialk@gmail.com.au","David Bomba","0060","€110,00","€0,00","","Archived","2017-02-07","","","€0,00","","","","0","0","","","Hello","A description","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0062","$11.00","$0.00","","Archived","2017-02-07","","","$0.00","","","","0","0","","","A New Product","A New Product","","","11","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0064","$33.00","$0.00","","Archived","2017-02-07","","","$0.00","","","","0","0","","","1","Third Described","","","3","11","","0","","0" +"Brett. Ange","","David Bomba","0068","€46,00","€0,00","","Archived","2017-02-09","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"Brett. Ange","","David Bomba","0068","€46,00","€0,00","","Archived","2017-02-09","","","€0,00","","","","0","0","","","Save","Grace","","","36","1","","0","","0" +"Alicia Cox","","David Bomba","0070","€11,00","€0,00","","Archived","2017-02-09","","","€0,00","","","","0","0","","","A New Product","A New Product","","","11","1","","0","","0" +"Angelique","","David Bomba","0072","€26,00","€0,00","","Archived","2017-02-09","","","€0,00","","","","0","0","","","Doggie","Doggy dog style","","","1","1","","0","","0" +"Angelique","","David Bomba","0072","€26,00","€0,00","","Archived","2017-02-09","","","€0,00","","","","0","0","","","Hidden","Costs","","","25","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0073","$3.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"Test","g@gmail.com","David Bomba","0074","$10.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0075","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0075","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10","Doodle","","","100","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0075","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0076","$13.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0076","$13.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0077","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0077","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10","Doodle","","","100","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0077","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0078","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0078","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10","Doodle","","","100","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0078","$113.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0079","$10.00","$0.00","","Archived","2017-02-21","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0086","€13,00","€13,00","","Archived","2017-02-21","","","€0,00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0086","€13,00","€13,00","","Archived","2017-02-21","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0087","€13,00","€10,00","","Archived","2017-02-21","","","€0,00","","","","0","0","","","1","Third Described","","","3","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0087","€13,00","€10,00","","Archived","2017-02-21","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0088","10.00 OMR","10.00 OMR","","Archived","2017-02-23","","","0.00 OMR","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0089","$10.00","$10.00","","Archived","2017-02-23","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0092","€1.432,74","€1.432,74","","Archived","","","","€0,00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0092","€1.432,74","€1.432,74","","Archived","","","","€0,00","","","","0","0","","","A New Product","A New Product","","","11","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0092","€1.432,74","€1.432,74","","Archived","","","","€0,00","","","","0","0","","","Save","Grace","","","36","31","yeh","9","VAT","17.5" +"1234","","David Bomba","0093","€10,00","€10,00","","Archived","2017-03-14","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0095","$120.00","$120.00","","Archived","2017-04-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0095","$120.00","$120.00","","Archived","2017-04-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0095","$120.00","$120.00","","Archived","2017-04-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0096","$137.45","$137.45","","Archived","2017-04-11","2017-04-04","","$0.00","","","","0","0","","","10","Green Men","","","10","2","VAT","17.5","","0" +"123 3434","Turd@gmail.co","David Bomba","0096","$137.45","$137.45","","Archived","2017-04-11","2017-04-04","","$0.00","","","","0","0","","","A new Product","The best product in the world!","","","10","5","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0096","$137.45","$137.45","","Archived","2017-04-11","2017-04-04","","$0.00","","","","0","0","","","A New Product","A New Product","","","11","4","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0097","$23.50","$23.50","","Archived","2017-04-11","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0097","$23.50","$23.50","","Archived","2017-04-11","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0098","$24.68","$24.68","","Archived","2017-04-11","","","$0.00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"123 3434","Turd@gmail.co","David Bomba","0098","$24.68","$24.68","","Archived","2017-04-11","","","$0.00","","","","0","0","","","A New Product","A New Product","","","11","1","","0","","0" +"1234","","David Bomba","0099","€21,00","€21,00","","Archived","2017-04-11","","","€0,00","","","","0","0","","","123","Spilt milk","","","9.17","1","yeh","9","","0" +"1234","","David Bomba","0099","€21,00","€21,00","","Archived","2017-04-11","","","€0,00","","","","0","0","","","A New Product","A New Product","","","10.09","1","yeh","9","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0100","11,316.43 OMR","11,316.43 OMR","","Archived","2017-04-11","","","0.00 OMR","","","","0","0","","","","## The First Project The First ### 04/Apr/2017 1:52 pm - 2:30 pm","","","50","192.62","VAT","17.5","","0" +"Craig Work","","David Bomba","0103","€10,00","€10,00","","Archived","2017-04-12","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0104","20.00 OMR","20.00 OMR","","Archived","2017-04-12","","","0.00 OMR","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0104","20.00 OMR","20.00 OMR","","Archived","2017-04-12","","","0.00 OMR","","","","0","0","","","A new Product","The best product in the world!","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0105","€10,00","€10,00","dfdf","Archived","","2017-04-20","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0109","€10,00","€10,00","","Archived","2017-04-26","","","€0,00","","","","0","0","","","10a","Green Men","","","10","1","","0","","0" +"Molly -top Malala -pop","mal@gmail.com","David Bomba","0110","$11.75","$11.75","","Archived","2017-05-04","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0111","€52,30","€52,30","","Archived","2017-05-10","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0111","€52,30","€52,30","","Archived","2017-05-10","","","€0,00","","","","0","0","","","Save","Grace","","","36","1","","0","VAT","17.5" +"1234 SMS","email@oi.oi","David Bomba","0112","€10,00","€0,00","dfdf","Archived","2017-05-12","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0113","€10,00","€0,00","dfdf","Archived","2017-05-12","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0114","€10,00","€0,00","dfdf","Archived","2017-05-12","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0115","€10,00","€10,00","dfdf","Archived","2017-05-12","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0116","€30,00","€30,00","ui","Archived","2017-06-02","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0116","€30,00","€30,00","ui","Archived","2017-06-02","","","€0,00","","","","0","0","","","A New Product","The best product in the world!","","","10","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0116","€30,00","€30,00","ui","Archived","2017-06-02","","","€0,00","","","","0","0","","","Malak","E la Malaka","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0118","€10,00","€10,00","","Archived","2017-06-14","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0119","€35,18","€35,18","","Archived","2017-06-21","","","€0,00","","","","0","0","","","123","Spilt milk","","","7.16","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0119","€35,18","€35,18","","Archived","2017-06-21","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","VAT","17.5","VAT 17.5 % Inclusive","17.5" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0119","€35,18","€35,18","","Archived","2017-06-21","","","€0,00","","","","0","0","","","10a","Green Men","","","10.21","1","VAT","17.5","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0120","€117,50","€117,50","","Archived","2017-06-21","","","€0,00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0120","$120.00","$0.00","","Archived","2017-07-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0120","$120.00","$0.00","","Archived","2017-07-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0120","$120.00","$0.00","","Archived","2017-07-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0121","€11,27","€11,27","","Archived","2017-07-12","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0121","€11,27","€11,27","","Archived","2017-07-12","","","€0,00","","","","0","0","","","Doggie","Doggy dog style","","","1","1","VAT","17.5","yeh","9" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0122","€35,25","€35,25","","Archived","2017-07-13","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0122","€35,25","€35,25","","Archived","2017-07-13","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0122","€35,25","€35,25","","Archived","2017-07-13","","","€0,00","","","","0","0","","","A New Product","The best product in the world!","","","10","1","","0","","0" +"A Street Dave names desire","turbo124@gmail.com","David Bomba","0122","€35,25","€35,25","","Archived","2017-07-13","","","€0,00","","","","0","0","","","","description","","","10","0","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0123","8.51 OMR","8.51 OMR","","Archived","2017-07-24","","","0.00 OMR","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0124","€8,51","€8,51","","Archived","2017-08-01","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0125","$120.00","$120.00","","Archived","2017-08-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0125","$120.00","$120.00","","Archived","2017-08-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0125","$120.00","$120.00","","Archived","2017-08-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"1234 SMS","email@oi.oi","David Bomba","0128","€1.463,60","€100,00","","Archived","2017-08-07","","","€0,00","","","","0","0","","","10a","Green Men","","","10.21","122","VAT","17.5","","0" +"First Last","last@mgil.com","David Bomba","0129","$10.00","$10.00","","Archived","2017-08-10","","","$0.00","","","","0","0","","","123","123","","","10","1","","0","","0" +"1234","","David Bomba","0130","€23,51","€23,51","","Archived","2017-08-15","","","€0,00","","","","0","0","","","10","Green Men","","","1.5","10","","0","","0" +"1234","","David Bomba","0130","€23,51","€23,51","","Archived","2017-08-15","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0133","€17,02","€13,02","","Archived","2017-09-02","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0133","€17,02","€13,02","","Archived","2017-09-02","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0135","€40,51","€0,00","","Archived","2017-09-02","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0135","€40,51","€0,00","","Archived","2017-09-02","","","€0,00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"David Bomba","david@romulus.com.au","David Bomba","0135","€40,51","€0,00","","Archived","2017-09-02","","","€0,00","","","","0","0","","","123","123","","","10","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0135","€40,51","€0,00","","Archived","2017-09-02","","","€0,00","","","","0","0","","","Malak","E la Malaka","","","10","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0138","€40,51","€8,51","","Archived","2017-09-13","","","€0,00","","","","0","0","","","arse","arsewwwh","","","20","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0138","€40,51","€8,51","","Archived","2017-09-13","","","€0,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"David Bomba","david@romulus.com.au","David Bomba","0138","€40,51","€8,51","","Archived","2017-09-13","","","€0,00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0139","€20,51","€0,00","","Archived","2017-09-20","","","€10,00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0139","€20,51","€0,00","","Archived","2017-09-20","","","€10,00","","","","0","0","","","10","Green Men","","","8.51","1","","0","","0" +"Test","g@gmail.com","David Bomba","0141","$9.00","$0.00","","Sent","2017-10-06","","","$0.00","","","","0","0","","","A New Product","A New Product","","","1","1","","0","","0" +"Test","g@gmail.com","David Bomba","0141","$9.00","$0.00","","Sent","2017-10-06","","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0142","30.51 OMR","30.51 OMR","","Archived","2017-10-11","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0142","30.51 OMR","30.51 OMR","","Archived","2017-10-11","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0142","30.51 OMR","30.51 OMR","","Archived","2017-10-11","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0143","$10.10","$1.10","popopo","Partial","2017-10-13","","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0143","$10.10","$1.10","popopo","Partial","2017-10-13","","","$0.00","","","","0","0","","","Surcharge","Online Payment Surcharge","","","0.1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0144","$10.00","$12.00","","Archived","2017-10-17","","","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"First Last","last@mgil.com","David Bomba","0145","$12.00","$5.50","","Archived","2017-11-01","","","$0.00","","","","0","0","","","1","2","","","10","1","exclusive","10","exclusive","10" +"A Dave","turbo124@gmail.com","David Bomba","R0146","$120.00","$0.00","","Sent","2017-11-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0146","$120.00","$0.00","","Sent","2017-11-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0146","$120.00","$0.00","","Sent","2017-11-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"First Last","last@mgil.com","David Bomba","0147","$24.15","$0.00","","Archived","2017-11-07","2017-11-14","","$0.00","","public","private","0","0","","","Drag","Dog","","","2","1","VAT","17.5","","0" +"First Last","last@mgil.com","David Bomba","0147","$24.15","$0.00","","Archived","2017-11-07","2017-11-14","","$0.00","","public","private","0","0","","","12345","123456","","","10","1","yeh","9","","0" +"First Last","last@mgil.com","David Bomba","0147","$24.15","$0.00","","Archived","2017-11-07","2017-11-14","","$0.00","","public","private","0","0","","","123","123","","","10","1","yeh","9","","0" +"First Last","last@mgil.com","David Bomba","0148","$10.00","$0.00","","Archived","2017-11-19","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0149","30.51 OMR","0.00 OMR","","Sent","2017-11-19","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0149","30.51 OMR","0.00 OMR","","Sent","2017-11-19","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0149","30.51 OMR","0.00 OMR","","Sent","2017-11-19","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0150","20,51 €","5,21 €","","Partial","2017-11-26","","","0,00 €","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"<48","david@romulus.com.au","David Bomba","0150","20,51 €","5,21 €","","Partial","2017-11-26","","","0,00 €","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"Test","g@gmail.com","David Bomba","0151","$7.51","$0.00","","Sent","2017-11-26","","$1.00","$0.00","","","","0","0","","","A new Product","The best product in the world!","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0151","$7.51","$0.00","","Sent","2017-11-26","","$1.00","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"Test","g@gmail.com","David Bomba","0151","$7.51","$0.00","","Sent","2017-11-26","","$1.00","$0.00","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0152","$120.00","$0.00","","Sent","2017-12-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0152","$120.00","$0.00","","Sent","2017-12-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0152","$120.00","$0.00","","Sent","2017-12-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0153","€12,75","€0,00","","Draft","2017-12-04","","","€0,00","","","","0","0","","","1","1","","","10","1","VAT","17.5","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0154","30.51 OMR","0.00 OMR","","Sent","2017-12-19","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0154","30.51 OMR","0.00 OMR","","Sent","2017-12-19","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0154","30.51 OMR","0.00 OMR","","Sent","2017-12-19","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0155","$120.00","$0.00","","Sent","2018-01-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0155","$120.00","$0.00","","Sent","2018-01-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0155","$120.00","$0.00","","Sent","2018-01-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0156","$474.39","$474.39","","Archived","2018-01-16","","","$0.00","","","","0","0","","","A new Product","The best product in the world!","","","5.65","10","VAT","17.5","","0" +"A Dave","turbo124@gmail.com","David Bomba","0156","$474.39","$474.39","","Archived","2018-01-16","","","$0.00","","","","0","0","","","jshw","zbhws","","","360","1","exclusive","10","","0" +"A Dave","turbo124@gmail.com","David Bomba","0156","$474.39","$474.39","","Archived","2018-01-16","","","$0.00","","","","0","0","","","asd","asd","","","12","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0157","€120,00","€0,00","","Sent","2018-01-24","2018-05-24","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0157","€120,00","€0,00","","Sent","2018-01-24","2018-05-24","","€0,00","","","","0","0","","","blueblue","descy","","","10","11","exclusive","10","","0" +"Test","g@gmail.com","David Bomba","0159","$130.00","$10.00","","Partial","2018-01-24","2018-05-24","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0159","$130.00","$10.00","","Partial","2018-01-24","2018-05-24","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Test","g@gmail.com","David Bomba","0159","$130.00","$10.00","","Partial","2018-01-24","2018-05-24","","$0.00","","","","0","0","","","1234","12355","","","5","22","","0","","0" +"Test","g@gmail.com","David Bomba","0160","$2,000.00","$8.00","","Archived","2018-01-24","2018-05-24","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","200","10","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0161","$28.51","$28.51","","Archived","2018-01-27","2018-05-27","","$0.00","","","","0","0","","","1","1","","","10","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0161","$28.51","$28.51","","Archived","2018-01-27","2018-05-27","","$0.00","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0161","$28.51","$28.51","","Archived","2018-01-27","2018-05-27","","$0.00","","","","0","0","","","1234","12355","","","10","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0162","€20,00","€5,60","","Partial","2018-01-29","2018-05-29","","€0,00","","","","0","0","","","1","1","","","10","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","0162","€20,00","€5,60","","Partial","2018-01-29","2018-05-29","","€0,00","","","","0","0","","","1234","12355","","","10","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0163","€28,51","€28,51","","Archived","2018-01-29","2018-05-29","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0163","€28,51","€28,51","","Archived","2018-01-29","2018-05-29","","€0,00","","","","0","0","","","1234","12355","","","10","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0163","€28,51","€28,51","","Archived","2018-01-29","2018-05-29","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0166","220,00 €","70,00 €","","Partial","2018-01-30","2018-05-30","","0,00 €","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0166","220,00 €","70,00 €","","Partial","2018-01-30","2018-05-30","","0,00 €","","","","0","0","","","123","123","","","10","21","yeh","9","","0" +"<48","david@romulus.com.au","David Bomba","0167","17,24 €","18,51 €","","Archived","2018-01-30","2018-02-05","","0,00 €","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0167","17,24 €","18,51 €","","Archived","2018-01-30","2018-02-05","","0,00 €","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0169","€20,00","€0,00","","Draft","2018-02-06","2018-02-12","","€0,00","","","","0","0","","","1","1","","","10","1","exclusive","10","","0" +"1234 SMS","oh@no.com","David Bomba","0169","€20,00","€0,00","","Draft","2018-02-06","2018-02-12","","€0,00","","","","0","0","","","1","1","","","10","1","exclusive","10","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","101","Green Men cxxccc And then you wonder why people want to slay the mob kill the masses and choke the weary","","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","Aaa","Sss","","","1","0","VAT","17.5","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","1","","","","1","13","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","sgsfg","adfa","","","9.460000000000001","1","VAT","17.5","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Green Men cxxccc And then you wonder why people want to slay the mob kill the masses and choke the weary Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","1","VAT","17.5","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","Test","Testing","","","34","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","5","123","31213","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","6","123 Green Men cxxccc And then you wonder why people want to slay the mob kill the masses and choke the weary","12","123123","0","0","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0170","$67.02","$67.02","","Archived","2018-02-10","2018-02-16","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 23-September-2019","","","0.66","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","1234","12355","","","5","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","notax","asasa","","","12","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","1","","","","12","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","3","","","","0","0","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","1","","","","12","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","12345","123456","","","10","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","Aaa","Sss","","","2","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","blueblue","descy","","","10","1","exclusive","10","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","New","Sensation","","","30","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","Newbie","Newbie","","","10","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","Drag","Dog","","","2","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","arse","arsewwwh","","","20","1","","0","","0" +"Alicia Cox","","David Bomba","0171","€129,48","€0,00","","Archived","2018-02-18","2018-02-23","","€0,00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","1234","12355","","","5","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","notax","asasa","","","12","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","1","","","","12","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","3","","","","0","0","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","1","","","","12","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","12345","123456","","","10","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","Aaa","Sss","","","2","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","blueblue","descy","","","10","1","exclusive","10","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","New","Sensation","","","30","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","Newbie","Newbie","","","10","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","Drag","Dog","","","2","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","arse","arsewwwh","","","20","1","","0","","0" +"Alicia Cox","","David Bomba","0172","€129,48","€129,48","","Archived","2018-03-01","","","€0,00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0173","$120.00","$0.00","","Sent","2018-03-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0173","$120.00","$0.00","","Sent","2018-03-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0173","$120.00","$0.00","","Sent","2018-03-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","credit-0001","€-113,12","€0,00","","Viewed","2018-03-06","","","€0,00","","","","0","0","","","1","","","","-112","1","","0","","0" +"Dave Bomba ","turbo124@gmail.com","David Bomba","credit-0001","€-113,12","€0,00","","Viewed","2018-03-06","","","€0,00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 08-December-2019","","","-1.12","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0174","$20.00","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0174","$20.00","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","1234","12355","","","5","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0174","$20.00","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","1234","12355","","","5","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0175","$10.00","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0176","$5.00","$0.00","","Sent","2018-03-18","","","$0.00","","","","0","0","","","1234","12355","","","5","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","Drag","Dog","","","2","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","notax","asasa","","","12","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","Test","Testing","","","34","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","notax","asasa","","","12","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","12345","123456","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Dave","turbo124@gmail.com","David Bomba","0177","$135.48","$0.00","","Viewed","2018-03-18","","","$0.00","","","","0","0","","","5","","","","0","0","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0178","$30.00","$0.00","","Sent","2018-03-26","","","$0.00","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Dave","turbo124@gmail.com","David Bomba","0178","$30.00","$0.00","","Sent","2018-03-26","","","$0.00","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0178","$30.00","$0.00","","Sent","2018-03-26","","","$0.00","","","","0","0","","","12345","123456","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0179","30.51 OMR","0.00 OMR","","Sent","2018-03-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0179","30.51 OMR","0.00 OMR","","Sent","2018-03-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0179","30.51 OMR","0.00 OMR","","Sent","2018-03-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0181","160.00 OMR","0.00 OMR","","Archived","2018-04-01","2018-04-04","","0.00 OMR","","","","0","0","","","Hidden","Costs","","","25","2","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0181","160.00 OMR","0.00 OMR","","Archived","2018-04-01","2018-04-04","","0.00 OMR","","","","0","0","","","10","Green Men","","","10","11","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0182","$118.80","$0.00","","Sent","2018-04-03","2018-04-18","1.00%","$10.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0182","$118.80","$0.00","","Sent","2018-04-03","2018-04-18","1.00%","$10.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0182","$118.80","$0.00","","Sent","2018-04-03","2018-04-18","1.00%","$10.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0183","$108.24","$108.24","","Archived","2018-04-10","","","$0.00","","","","0","0","","","101","Green Men cxxccc","","","7.24","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0183","$108.24","$108.24","","Archived","2018-04-10","","","$0.00","","","","0","0","","","10","Green Men","","","10","9","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0183","$108.24","$108.24","","Archived","2018-04-10","","","$0.00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0183","$108.24","$108.24","","Archived","2018-04-10","","","$0.00","","","","0","0","","","Space Cadets","M Alida","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0185","$155.00","$0.00","","Sent","2018-04-21","","","$0.00","","","","55","0","44","44","arse","arsewwwh","","","20","5","","0","","0" +"<48","david@romulus.com.au","David Bomba","0186","30,00 €","0,00 €","","Draft","2018-04-22","","","0,00 €","","","","25","0","3254","345","1234","12355","","","5","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0187","30.51 OMR","0.00 OMR","","Sent","2018-04-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0187","30.51 OMR","0.00 OMR","","Sent","2018-04-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0187","30.51 OMR","0.00 OMR","","Sent","2018-04-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0188","€3,00","€0,00","","Sent","2018-04-29","","€1,00","€0,00","","","","0","0","","","1234","12355","","","5","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0189","€28,51","€0,00","","Sent","2018-05-01","","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0189","€28,51","€0,00","","Sent","2018-05-01","","","€0,00","","","","0","0","","","1234","12355","","","10","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0189","€28,51","€0,00","","Sent","2018-05-01","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0190","$120.00","$0.00","","Sent","2018-05-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0190","$120.00","$0.00","","Sent","2018-05-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0190","$120.00","$0.00","","Sent","2018-05-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0191","19,41 €","0,00 €","","Draft","2018-05-11","","","0,00 €","","","","0","0","","","10","Green Men","","","9.460000000000001","1","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0191","19,41 €","0,00 €","","Draft","2018-05-11","","","0,00 €","","","","0","0","","","1234","12355","","","10","1","test 7.25","7.25","yeh","9" +"<48","david@romulus.com.au","David Bomba","0192","19,41 €","0,00 €","","Sent","2018-05-28","","","0,00 €","","","","0","0","","","10","Green Men","","","9.460000000000001","1","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0192","19,41 €","0,00 €","","Sent","2018-05-28","","","0,00 €","","","","0","0","","","1234","12355","","","10","1","test 7.25","7.25","yeh","9" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0194","30.51 OMR","0.00 OMR","","Sent","2018-05-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0194","30.51 OMR","0.00 OMR","","Sent","2018-05-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0194","30.51 OMR","0.00 OMR","","Sent","2018-05-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0195","$120.00","$0.00","","Viewed","2018-06-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0195","$120.00","$0.00","","Viewed","2018-06-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0195","$120.00","$0.00","","Viewed","2018-06-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"Belinda Dj Deb","david@romulus.com.au","David Bomba","0196","€12,00","€0,00","","Sent","2018-06-21","","","€0,00","","","","0","0","","","1","","","","12","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0197","30.51 OMR","30.51 OMR","","Archived","2018-06-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0197","30.51 OMR","30.51 OMR","","Archived","2018-06-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0197","30.51 OMR","30.51 OMR","","Archived","2018-06-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"1","","David Bomba","0198","€4,00","€0,00","","Archived","2018-07-01","","","€0,00","","","","0","0","","","1","1","1","1","0","3","","0","","0" +"1","","David Bomba","0198","€4,00","€0,00","","Archived","2018-07-01","","","€0,00","","","","0","0","","","1","2","2","2","2","2","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0199","$120.00","$120.00","","Archived","2018-07-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0199","$120.00","$120.00","","Archived","2018-07-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0199","$120.00","$120.00","","Archived","2018-07-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","credit-0002","-2.000,00 €","0,00 €","","Draft","2018-07-20","","","0,00 €","","","","0","0","","","retainer","","","","-2000","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0200","30.51 OMR","0.00 OMR","","Sent","2018-07-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0200","30.51 OMR","0.00 OMR","","Sent","2018-07-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","R0200","30.51 OMR","0.00 OMR","","Sent","2018-07-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0201","$120.00","$0.00","","Sent","2018-08-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0201","$120.00","$0.00","","Sent","2018-08-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","R0201","$120.00","$0.00","","Sent","2018-08-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0202","€9,46","€0,00","","Sent","2018-08-04","","","€0,00","","","","0","0","","","10","Green Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","1","","0","","0" +"Alicia Cox","","David Bomba","0203","€10,00","€0,00","","Draft","2018-08-20","","","€0,00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0204","1,00 €","0,00 €","","Sent","2018-08-25","","","0,00 €","","","","0","0","","","1","","","","1","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0205","30.51 OMR","0.00 OMR","","Sent","2018-08-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0205","30.51 OMR","0.00 OMR","","Sent","2018-08-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0205","30.51 OMR","0.00 OMR","","Sent","2018-08-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","credit-0003","-1.000,00 €","0,00 €","","Draft","2018-08-30","","","0,00 €","","","","0","0","","","1","1","","","-10","100","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0206","$120.00","$0.00","","Sent","2018-09-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0206","$120.00","$0.00","","Sent","2018-09-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0206","$120.00","$0.00","","Sent","2018-09-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","1","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","1234","12355","","","10","2","test 7.25","7.25","yeh","9" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","10","Green Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","3","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","4","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","5","","","","100","5","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Test","Testing","","","34","6","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","xaczxcz","2323","","","12","7","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","12","232","","","12","8","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Save","Grace","","","36","9","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Test","Testing","","","34","10","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Test","Testing","","","34","11","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","101","Green Men cxxccc","","","7.24","12","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","13","VAT","17.5","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Easy","Sunday","","","10","14","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Easy","Sunday","","","10","15","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Space Cadets","M Alida","","","10","61","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","Space Cadets","M Alida","","","10","17","","0","","0" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","1234","12355","","","10","18","test 7.25","7.25","yeh","9" +"<48","david@romulus.com.au","David Bomba","0207","5.477,44 €","0,00 €","","Sent","2018-09-21","","","0,00 €","","","","0","0","","","arse","arsewwwh","","","200","10","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0208","30.51 OMR","0.00 OMR","","Sent","2018-09-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0208","30.51 OMR","0.00 OMR","","Sent","2018-09-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0208","30.51 OMR","0.00 OMR","","Sent","2018-09-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0209","$120.00","$0.00","","Sent","2018-10-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0209","$120.00","$0.00","","Sent","2018-10-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0209","$120.00","$0.00","","Sent","2018-10-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0210","500,00 €","500,00 €","","Archived","2018-10-09","","","0,00 €","","","","0","0","","","1","1","1","","500","1","","0","","0" +"Craig Work","david@romulus.com.au","David Bomba","0211","€200,00","€200,00","","Archived","2018-10-15","","","€0,00","","","","0","0","","","1","1","1","1","200","1","","0","","0" +"Craig Work","david@romulus.com.au","David Bomba","credit-0004","€-200,00","€0,00","","Sent","2018-10-15","","","€0,00","","","","0","0","","","1","1","","","-100","2","","0","","0" +"Craig Work","david@romulus.com.au","David Bomba","0212","€472,00","€0,00","","Sent","2018-10-15","","","€0,00","","","","0","0","","","1","1","1","","236","2","","0","","0" +"Craig Work","david@romulus.com.au","David Bomba","credit-0005","€100,00","€0,00","","Sent","2018-10-15","","","€0,00","","","","0","0","","","1","100","","","100","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0213","€1.500,00","€0,00","","Sent","2018-10-19","","","€0,00","","","","0","0","","","Advertising","","","","1500","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0215","30.51 OMR","0.00 OMR","","Sent","2018-10-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0215","30.51 OMR","0.00 OMR","","Sent","2018-10-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0215","30.51 OMR","0.00 OMR","","Sent","2018-10-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0216","$120.00","$0.00","","Sent","2018-11-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0216","$120.00","$0.00","","Sent","2018-11-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0216","$120.00","$0.00","","Sent","2018-11-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0217","30.51 OMR","0.00 OMR","","Sent","2018-11-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0217","30.51 OMR","0.00 OMR","","Sent","2018-11-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0217","30.51 OMR","0.00 OMR","","Sent","2018-11-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0218","$121.20","$121.20","","Archived","2018-12-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0218","$121.20","$121.20","","Archived","2018-12-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0218","$121.20","$121.20","","Archived","2018-12-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0218","$121.20","$121.20","","Archived","2018-12-03","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 22-September-2019","","","1.2","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0219","30.51 OMR","0.00 OMR","","Sent","2018-12-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0219","30.51 OMR","0.00 OMR","","Sent","2018-12-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0219","30.51 OMR","0.00 OMR","","Sent","2018-12-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0220","$121.20","$121.20","","Archived","2019-01-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0220","$121.20","$121.20","","Archived","2019-01-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0220","$121.20","$121.20","","Archived","2019-01-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0220","$121.20","$121.20","","Archived","2019-01-03","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 22-September-2019","","","1.2","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0221","999.999.999,00 €","0,00 €","","Draft","2019-01-09","","","0,00 €","","","","0","0","","","1","100","","","0","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0221","999.999.999,00 €","0,00 €","","Draft","2019-01-09","","","0,00 €","","","","0","0","","","1","1","","","999999999","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0222","28.51 OMR","28.51 OMR","","Archived","2019-01-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0222","28.51 OMR","28.51 OMR","","Archived","2019-01-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0222","28.51 OMR","28.51 OMR","","Archived","2019-01-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0223","$120.00","$120.00","","Archived","2019-02-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0223","$120.00","$120.00","","Archived","2019-02-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0223","$120.00","$120.00","","Archived","2019-02-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0224","30.51 OMR","0.00 OMR","","Sent","2019-02-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0224","30.51 OMR","0.00 OMR","","Sent","2019-02-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0224","30.51 OMR","0.00 OMR","","Sent","2019-02-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0225","$121.20","$121.20","","Archived","2019-03-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0225","$121.20","$121.20","","Archived","2019-03-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0225","$121.20","$121.20","","Archived","2019-03-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0225","$121.20","$121.20","","Archived","2019-03-03","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","1.2","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0226","9,50 €","0,00 €","","Sent","2019-03-14","","","0,00 €","","","","0","0","","","1","","12","1","1","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0226","9,50 €","0,00 €","","Sent","2019-03-14","","","0,00 €","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0227","30.51 OMR","0.00 OMR","","Sent","2019-03-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0227","30.51 OMR","0.00 OMR","","Sent","2019-03-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0227","30.51 OMR","0.00 OMR","","Sent","2019-03-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0228","$272.70","$272.70","","Archived","2019-04-03","","","$0.00","","","","150","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0228","$272.70","$272.70","","Archived","2019-04-03","","","$0.00","","","","150","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0228","$272.70","$272.70","","Archived","2019-04-03","","","$0.00","","","","150","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0228","$272.70","$272.70","","Archived","2019-04-03","","","$0.00","","","","150","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","2.7","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0229","$22.00","$0.00","","Sent","2019-04-08","","","$0.00","","","","1","1","","","1","","","","10","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0229","$22.00","$0.00","","Sent","2019-04-08","","","$0.00","","","","1","1","","","1","","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0230","10,00 €","0,00 €","","Sent","2019-04-22","","","0,00 €","","","","0","0","","","1","","","","10","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0231","30.51 OMR","0.00 OMR","","Sent","2019-04-28","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0231","30.51 OMR","0.00 OMR","","Sent","2019-04-28","","","0.00 OMR","","","","0","0","","","1","1","","","10","1","exclusive","10","exclusive","10" +"A Pounder Name","david@invoiceninja.com","David Bomba","0231","30.51 OMR","0.00 OMR","","Sent","2019-04-28","","","0.00 OMR","","","","0","0","","","123","123","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0233","$121.20","$121.20","","Archived","2019-05-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0233","$121.20","$121.20","","Archived","2019-05-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0233","$121.20","$121.20","","Archived","2019-05-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","0233","$121.20","$121.20","","Archived","2019-05-03","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","1.2","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","1","1","1","1","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","11","1","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","11","","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","1","","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","11","","1","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Green Men cxxccc And then you wonder why people want to slay the mob kill the masses and choke the weary Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","323","","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","3232","232","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","2323","","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","1234","12355","","","10","1","test 7.25","7.25","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","123","123","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","0234","39,46 €","0,00 €","","Viewed","2019-05-03","","","0,00 €","","","","0","0","","","123","","","","0","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0235","101,00 €","101,00 €","","Archived","2019-05-12","","","0,00 €","","","","0","0","","","1","","","1","1","101","","0","","0" +"<48","david@romulus.com.au","David Bomba","0236","100,00 €","100,00 €","","Archived","2019-05-14","","","0,00 €","","","","0","0","","","1","","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0001","$121.20","$121.20","","Archived","2019-06-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0001","$121.20","$121.20","","Archived","2019-06-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0001","$121.20","$121.20","","Archived","2019-06-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0001","$121.20","$121.20","","Archived","2019-06-03","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","1.2","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0002","10,00 €","0,00 €","","Sent","2019-06-10","","","0,00 €","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0003","0,00 €","0,00 €","","Sent","2019-06-10","","","0,00 €","","","","0","0","","","1","","","","0","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0004","10,10 €","10,10 €","","Paid","2019-06-13","","","0,00 €","","","","0","0","","","1","","","","0","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0004","10,10 €","10,10 €","","Paid","2019-06-13","","","0,00 €","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0004","10,10 €","10,10 €","","Paid","2019-06-13","","","0,00 €","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 24-September-2019","","","0.1","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","33232-0001","€18,70","€18,70","","Paid","2019-06-15","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","33232-0001","€18,70","€18,70","","Paid","2019-06-15","","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","33232-0001","€18,70","€18,70","","Paid","2019-06-15","","","€0,00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 23-September-2019","","","0.19","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","dd-0002","€28,25","€28,25","","Archived","2019-06-16","","","€0,00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","dd-0002","€28,25","€28,25","","Archived","2019-06-16","","","€0,00","","","","0","0","","","101","Green Men cxxccc","","","8.51","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","dd-0002","€28,25","€28,25","","Archived","2019-06-16","","","€0,00","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Green Men cxxccc And then you wonder why people want to slay the mob kill the masses and choke the weary Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","1","","0","","0" +"Oztralia","turbo124@gmail.com","David Bomba","dd-0002","€28,25","€28,25","","Archived","2019-06-16","","","€0,00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 23-September-2019","","","0.28","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0005","9,55 €","9,55 €","","Archived","2019-06-15","","","0,00 €","","","","0","0","","","10sdgdfsgdfsgdfsg","Green Green Men cxxccc And then you wonder why people want to slay the mob kill the masses and choke the weary Mendsfgdfsgdfsgdfsg sdg dsfg dfsg dfs gds fg dsf gds fg dfsg","","","9.460000000000001","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0005","9,55 €","9,55 €","","Archived","2019-06-15","","","0,00 €","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 23-September-2019","","","0.09","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0006","0,00 €","0,00 €","","Sent","2019-06-15","","","0,00 €","","","","0","0","","","11","","1","","0","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0003","$121.20","$121.20","","Archived","2019-07-03","","","$0.00","","","","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0003","$121.20","$121.20","","Archived","2019-07-03","","","$0.00","","","","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0003","$121.20","$121.20","","Archived","2019-07-03","","","$0.00","","","","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0003","$121.20","$121.20","","Archived","2019-07-03","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","1.2","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0007","0,00 €","0,00 €","","Sent","2019-07-06","","","0,00 €","","","","0","0","","","1","","","","0","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0004","$121.20","$121.20","","Archived","2019-08-03","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0004","$121.20","$121.20","","Archived","2019-08-03","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0004","$121.20","$121.20","","Archived","2019-08-03","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","-0004","$121.20","$121.20","","Archived","2019-08-03","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","1.2","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","d-0001","$12.00","$0.00","","Sent","2019-08-16","","","$0.00","","","","0","0","","","1","1","1","2","3","4","","0","","0" +"A client name too","contact@gmail.com","David Bomba","d-0001","$12.00","$0.00","","Sent","2019-08-16","","","$0.00","","","","0","0","","","101","Green Men cxxccc","","","200","0","","0","","0" +"asa","ada@gmail.com","David Bomba","fdafdf","€1,01","€1,01","","Paid","2019-09-16","","","€0,00","","","","0","0","","","A new Product","A New Product","","","1","1","","0","","0" +"asa","ada@gmail.com","David Bomba","fdafdf","€1,01","€1,01","","Paid","2019-09-16","","","€0,00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 24-September-2019","","","0.01","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","adsas34","$122.41","$122.41","","Archived","2019-09-23","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","10","Green Men","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","adsas34","$122.41","$122.41","","Archived","2019-09-23","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","123","Spilt milk","","","10","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","adsas34","$122.41","$122.41","","Archived","2019-09-23","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","asd","RedMen","","","100","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","adsas34","$122.41","$122.41","","Archived","2019-09-23","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 20-September-2019","","","1.2","1","","0","","0" +"A Dave","turbo124@gmail.com","David Bomba","adsas34","$122.41","$122.41","","Archived","2019-09-23","","","$0.00","","sdgfsdgffd","gsdgsdgsd","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 22-September-2019","","","1.21","1","","0","","0" +"1","turbo124@gmail.com","David BoBo","132-0002","€10,00","€0,00","","Sent","2019-10-02","","","€0,00","","","","0","0","","","1","","","","1","10","","0","","0" +"1","turbo124@gmail.com","David BoBo","112-0003","€0,99","€0,00","","Sent","2019-10-01","","","€0,00","","","","0","0","","","1","1","1","1","1","1","","0","","0" +"1","turbo124@gmail.com","David BoBo","11-0004","€0,99","€0,00","","Sent","2019-10-02","","","€0,00","","","","0","0","","","1","1","1","1","1","1","","0","","0" +"1","turbo124@gmail.com","David BoBo","-0005","€0,99","€0,00","","Sent","2019-10-02","","","€0,00","","","","0","0","","","1","11","11","11","1","1","","0","","0" +"1","turbo124@gmail.com","David BoBo","-0005","€0,99","€0,00","","Sent","2019-10-02","","","€0,00","","","","0","0","","","1","","","","0","0","","0","","0" +"1","turbo124@gmail.com","David BoBo","-0007","€1,00","€1,00","","Paid","2019-10-04","","","€0,00","","","","0","0","","","1","11","11","11","1","1","","0","","0" +"1","turbo124@gmail.com","David BoBo","-0007","€1,00","€1,00","","Paid","2019-10-04","","","€0,00","","","","0","0","","","1","","","","0","0","","0","","0" +"1","turbo124@gmail.com","David BoBo","-0007","€1,00","€1,00","","Paid","2019-10-04","","","€0,00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 24/Mar/2020","","","0.01","1","","0","","0" +"<48","david@romulus.com.au","David Bomba","12-0237","16.964,11 €","16.964,11 €","","Paid","2019-10-10","","","0,00 €","","","","0","0","","","","","","","495.2","10","GST","10","","0" +"<48","david@romulus.com.au","David Bomba","12-0237","16.964,11 €","16.964,11 €","","Paid","2019-10-10","","","0,00 €","","","","0","0","","","","","","","97.83","1","GST","10","","0" +"<48","david@romulus.com.au","David Bomba","12-0237","16.964,11 €","16.964,11 €","","Paid","2019-10-10","","","0,00 €","","","","0","0","","","","","","","425.24","10","GST","10","","0" +"<48","david@romulus.com.au","David Bomba","12-0237","16.964,11 €","16.964,11 €","","Paid","2019-10-10","","","0,00 €","","","","0","0","","","","","","","817.72","9","GST","10","","0" +"<48","david@romulus.com.au","David Bomba","12-0237","16.964,11 €","16.964,11 €","","Paid","2019-10-10","","","0,00 €","","","","0","0","","","","","","","253.44","4","GST","10","","0" +"<48","david@romulus.com.au","David Bomba","12-0237","16.964,11 €","16.964,11 €","","Paid","2019-10-10","","","0,00 €","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 25-October-2019","","","167.96","1","","0","","0" +"1","turbo124@gmail.com","David Bomba","232320001-0238","€11,00","€11,00","","Paid","2019-11-25","","","€0,00","","","","0","0","","","12123","","","","11","1","","0","","0" +"1","turbo124@gmail.com","David Bomba","232320001-0238","€11,00","€11,00","","Paid","2019-11-25","","","€0,00","","","","0","0","","","2323","","","","0","1","","0","","0" +"1","turbo124@gmail.com","David Bomba","232320001-0238","€11,00","€11,00","","Paid","2019-11-25","","","€0,00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 24/Mar/2020","","","0.11","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0242","100.00 OMR","100.00 OMR","","Paid","2020-02-16","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","100","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0243","100.00 OMR","100.00 OMR","","Paid","2020-02-16","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","100","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0244","100.00 OMR","100.00 OMR","","Paid","2020-02-16","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","100","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0246","99.00 OMR","99.00 OMR","","Paid","2020-03-01","2020-09-01","","0.00 OMR","","","","0","0","","","1","","1","1","100","1","","0","","0" +"1234 SMS","oh@no.com","David Bomba","0249","€0,99","€0,00","","Archived","2020-05-30","","","€0,00","","","","0","0","","","","","","1","1","1","","0","","0" +"1","","David Bomba","0251","€0,00","€0,00","","Sent","2020-06-16","","","€0,00","","","","0","0","","","11","","1","","0","1","","0","","0" +"A Pounder Name","david@invoiceninja.com","David Bomba","0254","100.00 OMR","0.00 OMR","","Sent","2020-06-16","","","0.00 OMR","","","","0","0","","","101","Green Men cxxccc","","","100","1","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0256","$44.44","$44.44","","Paid","2020-06-16","","","$0.00","","","","0","0","","","","","","2","22","2","","0","","0" +"A client name too","contact@gmail.com","David Bomba","0256","$44.44","$44.44","","Paid","2020-06-16","","","$0.00","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 23/Aug/2020","","","0.44","1","","0","","0" +"123","","David Bomba","0257","€0,00","€0,00","","Sent","2020-06-16","","","€0,00","","","","0","0","","","33","","","","0","1","","0","","0" +"123","","David Bomba","0257","€0,00","€0,00","","Sent","2020-06-16","","","€0,00","","","","0","0","","","12","","","","1","0","","0","","0" +"123","","David Bomba","0258","€0,00","€0,00","123321","Sent","2020-06-20","","","€0,00","","","","0","0","","","33","","","","0","1","","0","","0" +"123","","David Bomba","0258","€0,00","€0,00","123321","Sent","2020-06-20","","","€0,00","","","","0","0","","","12","","","","1","0","","0","","0" +"<48","david@romulus.com.au","David Bomba","0260","103,00 €","103,00 €","","Paid","2020-08-30","","","0,00 €","","","","0","0","","","1","1","1","1","1","100","","0","","0" +"<48","david@romulus.com.au","David Bomba","0260","103,00 €","103,00 €","","Paid","2020-08-30","","","0,00 €","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 30/Aug/2020","","","3","1","exclusive","10","test 7.25","7.25" +"<48","david@romulus.com.au","David Bomba","0261","103,00 €","52,35 €","","Partial","2020-08-31","","","50,00 €","","","","0","0","","","1","1","1","1","1","100","","0","","0" +"<48","david@romulus.com.au","David Bomba","0261","103,00 €","52,35 €","","Partial","2020-08-31","","","50,00 €","","","","0","0","","","Gateway Fee Item","Gateway Fee Surcharge • 30/Aug/2020","","","3","1","exclusive","10","test 7.25","7.25" +"<48","david@romulus.com.au","David Bomba","0262","100,00 €","103,99 €","","Paid","2020-08-31","","","0,00 €","","","","0","0","","","1","1","1","1","1","100","","0","","0" +"<48","david@romulus.com.au","David Bomba","0263","100,00 €","0,00 €","","Sent","2020-08-31","","","0,00 €","","","","0","0","","","1","1","1","1","1","100","","0","","0" +"1","","David Bomba","0268","€2,00","€0,00","","Sent","2020-12-01","","","€0,00","","","","0","0","","","1","","","","1","1","","0","","0" +"1","","David Bomba","0268","€2,00","€0,00","","Sent","2020-12-01","","","€0,00","","","","0","0","","","1","","","","1","1","","0","","0" From 3419d7900f982f7abefcb7ad68407bc875873c4f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Dec 2020 21:35:42 +1100 Subject: [PATCH 09/87] Tests for importing CSV files --- app/Http/Controllers/ImportController.php | 19 ++++++++++++++++++- tests/Feature/Import/ImportCsvTest.php | 10 ++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 71d265a50c84..737c1829a657 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -38,6 +38,17 @@ class ImportController extends Controller * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\RequestBody( + * description="The CSV file", + * required=true, + * @OA\MediaType( + * mediaType="multipart/form-data", + * @OA\Schema( + * type="string", + * format="binary" + * ) + * ) + * ), * @OA\Response( * response=200, * description="Returns a reference to the file", @@ -68,6 +79,13 @@ class ImportController extends Controller //parse CSV $csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname())); + + $data['data'] = [ + 'hash' => $hash, + 'headers' => array_slice($csv_array, 0, 2) + ]; + + return response()->json($data); } @@ -79,7 +97,6 @@ class ImportController extends Controller } $csv = Reader::createFromString($csvfile); - //$csv->setHeaderOffset(0); //set the CSV header offset $stmt = new Statement(); $data = iterator_to_array($stmt->process($csv)); diff --git a/tests/Feature/Import/ImportCsvTest.php b/tests/Feature/Import/ImportCsvTest.php index b17c53684d30..377d7fc1b22e 100644 --- a/tests/Feature/Import/ImportCsvTest.php +++ b/tests/Feature/Import/ImportCsvTest.php @@ -37,10 +37,9 @@ class ImportCsvTest extends TestCase ThrottleRequests::class ); - $this->faker = \Faker\Factory::create(); + // $this->faker = \Faker\Factory::create(); - - $this->makeTestData(); + // $this->makeTestData(); $this->withoutExceptionHandling(); } @@ -49,7 +48,7 @@ class ImportCsvTest extends TestCase { $csv = file_get_contents(base_path().'/tests/Feature/Import/invoice.csv'); - return $this->getCsvData($csv); + $this->assertTrue(is_array($this->getCsvData($csv))); } @@ -61,7 +60,6 @@ class ImportCsvTest extends TestCase } $csv = Reader::createFromString($csvfile); - //$csv->setHeaderOffset(0); //set the CSV header offset $stmt = new Statement(); $data = iterator_to_array($stmt->process($csv)); @@ -78,7 +76,7 @@ class ImportCsvTest extends TestCase } } } -info(print_r($data,1)); + return $data; } } \ No newline at end of file From 2a1a9e2a166d85e2234cc1cd7678630e1f4ac990 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Dec 2020 21:47:52 +1100 Subject: [PATCH 10/87] Working on import --- app/Http/Requests/Import/PreImportRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Requests/Import/PreImportRequest.php b/app/Http/Requests/Import/PreImportRequest.php index b62acc2ab043..fdfb162e20af 100644 --- a/app/Http/Requests/Import/PreImportRequest.php +++ b/app/Http/Requests/Import/PreImportRequest.php @@ -30,7 +30,7 @@ class PreImportRequest extends Request { return [ - 'file' => 'required|mimes:csv' + 'file' => 'required|file|mimes:csv,txt' ]; } From 419b381c213ce92e1c7cd47239a6becfcb667357 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Dec 2020 22:23:29 +1100 Subject: [PATCH 11/87] Filter exceptions --- app/Exceptions/Handler.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index cdee20094ba0..05c74a747923 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -72,10 +72,6 @@ class Handler extends ExceptionHandler info('account table not found'); return; } - // if(Account::count() == 0){ - // info("handler - account table not found"); - // return; - // } if (app()->bound('sentry') && $this->shouldReport($exception)) { app('sentry')->configureScope(function (Scope $scope): void { @@ -95,12 +91,28 @@ class Handler extends ExceptionHandler }); // app('sentry')->setRelease(config('ninja.app_version')); - app('sentry')->captureException($exception); + + if($this->validException($exception)) + app('sentry')->captureException($exception); } parent::report($exception); } + private function validException($exception) + { + info("the exception is "); + info($exception->getMessage()); + + if(strpos($exception->getMessage(), 'file_put_contents') === TRUE) + return FALSE; + + if(strpos($exception->getMessage(), 'Permission denied') === TRUE) + return FALSE; + + return TRUE; + } + /** * Render an exception into an HTTP response. * From 1913318124f0ac26824a7c628d26e1c241c279c8 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Dec 2020 07:54:25 +1100 Subject: [PATCH 12/87] bump the import cache timeout from 10 minutes to 60 minutes --- app/Http/Controllers/ImportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 737c1829a657..6d9c7eeeb2c2 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -75,7 +75,7 @@ class ImportController extends Controller $hash = Str::random(32); //store the csv in cache with an expiry of 10 minutes - Cache::put($hash, base64_encode(file_get_contents($request->file('file')->getPathname())), 10); + Cache::put($hash, base64_encode(file_get_contents($request->file('file')->getPathname())), 60); //parse CSV $csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname())); From 0f861554f06f52e674c46a47cdd2b4c19c3373df Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Dec 2020 08:06:47 +1100 Subject: [PATCH 13/87] Fixes for exec and open_basedir checks --- app/Utils/SystemHealth.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/Utils/SystemHealth.php b/app/Utils/SystemHealth.php index 9b09f6b8947b..b32d1a14c1c4 100644 --- a/app/Utils/SystemHealth.php +++ b/app/Utils/SystemHealth.php @@ -78,9 +78,27 @@ class SystemHealth 'node_status' => self::checkNode(), 'cache_enabled' => self::checkConfigCache(), 'phantom_enabled' => (bool) config('ninja.phantomjs_pdf_generation'), + 'exec' => (bool) self::checkExecWorks(), + 'open_basedir' => (bool) self::checkOpenBaseDir(), ]; } + public static function checkOpenBaseDir() + { + if(strlen(ini_get('open_basedir') == 0)) + return true; + + return false; + } + + public static function checkExecWorks() + { + if(function_exists('exec')) + return true; + + return false; + } + public static function checkConfigCache() { if (env('APP_URL')) { From 8abce54d7e3a34b6d0cc9555a47711bcfeec8947 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Dec 2020 10:20:03 +1100 Subject: [PATCH 14/87] Fixes for customised language options for Preview Controller --- app/Exceptions/Handler.php | 6 ++++-- app/Http/Controllers/EmailController.php | 4 +--- app/Http/Controllers/PreviewController.php | 14 +++++++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 05c74a747923..1f71590459a8 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -101,8 +101,6 @@ class Handler extends ExceptionHandler private function validException($exception) { - info("the exception is "); - info($exception->getMessage()); if(strpos($exception->getMessage(), 'file_put_contents') === TRUE) return FALSE; @@ -110,6 +108,10 @@ class Handler extends ExceptionHandler if(strpos($exception->getMessage(), 'Permission denied') === TRUE) return FALSE; + if(strpos($exception->getMessage(), 'flock()') === TRUE) + return FALSE; + + return TRUE; } diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index 7bbbc959bf9b..8bd6648a7ad4 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -132,7 +132,7 @@ class EmailController extends BaseController } }); - $entity_obj->service()->markSent()->save(); + $entity_obj = $entity_obj->service()->markSent()->save(); $entity_obj->last_sent_date = now(); $entity_obj->save(); @@ -172,8 +172,6 @@ class EmailController extends BaseController $this->entity_transformer = RecurringInvoiceTransformer::class; } - $entity_obj->service()->markSent()->save(); - return $this->itemResponse($entity_obj); } } diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index d81d98629faf..9801fa1be649 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -20,11 +20,14 @@ use App\Models\InvoiceInvitation; use App\Services\PdfMaker\Design; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; +use App\Utils\Ninja; use App\Utils\PhantomJS\Phantom; use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesInvoiceHtml; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Response; +use Illuminate\Support\Facades\App; +use Illuminate\Support\Facades\Lang; class PreviewController extends BaseController { @@ -96,15 +99,16 @@ class PreviewController extends BaseController $entity_obj->load('client'); + App::setLocale($entity_obj->client->primary_contact()->preferredLocale()); + App::forgetInstance('translator'); + Lang::replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings())); + $html = new HtmlEngine($entity_obj->invitations()->first()); $design_namespace = 'App\Services\PdfMaker\Designs\\'.request()->design['name']; $design_class = new $design_namespace(); - // $designer = new Designer($entity_obj, $design_object, $entity_obj->client->getSetting('pdf_variables'), lcfirst($entity)); - // $html = $this->generateEntityHtml($designer, $entity_obj); - $state = [ 'template' => $design_class->elements([ 'client' => $entity_obj->client, @@ -141,6 +145,10 @@ class PreviewController extends BaseController private function blankEntity() { + + App::forgetInstance('translator'); + Lang::replace(Ninja::transformTranslations(auth()->user()->company()->settings)); + DB::beginTransaction(); $client = Client::factory()->create([ From d440d4421dfbce35cfcd6b70a729437391849e43 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Dec 2020 11:04:56 +1100 Subject: [PATCH 15/87] Fix for doubling client balance erroneously on emailing" --- app/Http/Controllers/EmailController.php | 2 -- app/Services/Invoice/MarkSent.php | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index 8bd6648a7ad4..e639340df6dd 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -132,8 +132,6 @@ class EmailController extends BaseController } }); - $entity_obj = $entity_obj->service()->markSent()->save(); - $entity_obj->last_sent_date = now(); $entity_obj->save(); diff --git a/app/Services/Invoice/MarkSent.php b/app/Services/Invoice/MarkSent.php index ed8c8daaa7f1..839f484f0dc6 100644 --- a/app/Services/Invoice/MarkSent.php +++ b/app/Services/Invoice/MarkSent.php @@ -37,6 +37,9 @@ class MarkSent extends AbstractService return $this->invoice; } +info("in mark sent"); +info($this->invoice->balance); + $this->invoice->markInvitationsSent(); $this->invoice->setReminder(); @@ -49,8 +52,12 @@ class MarkSent extends AbstractService ->updateBalance($this->invoice->amount) ->save(); +info($this->invoice->balance); + $this->client->service()->updateBalance($this->invoice->balance)->save(); +info($this->client->balance); + $this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance); event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars())); From 6f451b8924b31f471701a1a349800d4018acee3f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Dec 2020 20:46:29 +1100 Subject: [PATCH 16/87] Remove redundant info() Change document download route --- app/DataMapper/EmailTemplateDefaults.php | 1 - app/Filters/ClientFilters.php | 1 - .../ClientPortal/DocumentController.php | 9 +++------ app/Http/Controllers/EmailController.php | 2 +- app/Models/CompanyGateway.php | 10 +++++----- app/Services/Invoice/ApplyPayment.php | 15 +++++++-------- app/Services/Invoice/MarkSent.php | 7 ------- routes/client.php | 2 +- 8 files changed, 17 insertions(+), 30 deletions(-) diff --git a/app/DataMapper/EmailTemplateDefaults.php b/app/DataMapper/EmailTemplateDefaults.php index d7137ce7f1e7..721114771cff 100644 --- a/app/DataMapper/EmailTemplateDefaults.php +++ b/app/DataMapper/EmailTemplateDefaults.php @@ -173,7 +173,6 @@ class EmailTemplateDefaults public static function emailReminder1Subject() { - info("reminder 1 subject"); return ctrans('texts.reminder_subject', ['invoice'=>'$invoice.number', 'account'=>'$company.name']); } diff --git a/app/Filters/ClientFilters.php b/app/Filters/ClientFilters.php index 9221b5da4fdf..e367708d17f5 100644 --- a/app/Filters/ClientFilters.php +++ b/app/Filters/ClientFilters.php @@ -190,7 +190,6 @@ class ClientFilters extends QueryFilters * limit the user to only the invoices they have created */ if (Gate::denies('view-list', Client::class)) { - info('the gate!'); $query->where('clients.user_id', '=', $user->id); } diff --git a/app/Http/Controllers/ClientPortal/DocumentController.php b/app/Http/Controllers/ClientPortal/DocumentController.php index be7332e4d33d..ee485174bb5a 100644 --- a/app/Http/Controllers/ClientPortal/DocumentController.php +++ b/app/Http/Controllers/ClientPortal/DocumentController.php @@ -54,15 +54,12 @@ class DocumentController extends Controller return Storage::disk($document->disk)->download($document->url, $document->name); } - public function publicDownload(string $contact_key, Document $document) + public function publicDownload(string $document_hash) { - //return failure if the contact is not associated with the document - $contact = ClientContact::where('contact_key', $contact_key)->firstOrFail(); - if($contact->company_id == $document->company_id) + $document = Document::where('hash', $document_hash)->firstOrFail(); + return Storage::disk($document->disk)->download($document->url, $document->name); - - return response()->json(['message' => 'Access denied']); } public function downloadMultiple(DownloadMultipleDocumentsRequest $request) diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index e639340df6dd..580fbeb483a4 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -170,6 +170,6 @@ class EmailController extends BaseController $this->entity_transformer = RecurringInvoiceTransformer::class; } - return $this->itemResponse($entity_obj); + return $this->itemResponse($entity_obj->fresh()); } } diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index d5ee8ca346b2..1f06e03b64a5 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -280,7 +280,7 @@ class CompanyGateway extends BaseModel if ($fees_and_limits->fee_amount) { $fee += $fees_and_limits->fee_amount; - info("fee after adding fee amount = {$fee}"); + // info("fee after adding fee amount = {$fee}"); } if ($fees_and_limits->fee_percent) { @@ -289,7 +289,7 @@ class CompanyGateway extends BaseModel } else { $fee += round(($amount * $fees_and_limits->fee_percent / 100), 2); } - info("fee after adding fee percent = {$fee}"); + // info("fee after adding fee percent = {$fee}"); } /* Cap fee if we have to here. */ @@ -303,17 +303,17 @@ class CompanyGateway extends BaseModel if ($include_taxes) { if ($fees_and_limits->fee_tax_rate1) { $fee += round(($pre_tax_fee * $fees_and_limits->fee_tax_rate1 / 100), 2); - info("fee after adding fee tax 1 = {$fee}"); + // info("fee after adding fee tax 1 = {$fee}"); } if ($fees_and_limits->fee_tax_rate2) { $fee += round(($pre_tax_fee * $fees_and_limits->fee_tax_rate2 / 100), 2); - info("fee after adding fee tax 2 = {$fee}"); + // info("fee after adding fee tax 2 = {$fee}"); } if ($fees_and_limits->fee_tax_rate3) { $fee += round(($pre_tax_fee * $fees_and_limits->fee_tax_rate3 / 100), 2); - info("fee after adding fee tax 3 = {$fee}"); + // info("fee after adding fee tax 3 = {$fee}"); } } diff --git a/app/Services/Invoice/ApplyPayment.php b/app/Services/Invoice/ApplyPayment.php index ead9cd9b4135..0a67d4070b8f 100644 --- a/app/Services/Invoice/ApplyPayment.php +++ b/app/Services/Invoice/ApplyPayment.php @@ -36,14 +36,13 @@ class ApplyPayment extends AbstractService ->ledger() ->updatePaymentBalance($this->payment_amount * -1); - info("apply payment method - current client balance = {$this->payment->client->balance}"); + // info("apply payment method - current client balance = {$this->payment->client->balance}"); - info("reducing client balance by payment amount {$this->payment_amount}"); + // info("reducing client balance by payment amount {$this->payment_amount}"); $this->invoice->client->service()->updateBalance($this->payment_amount * -1)->save(); -// $this->invoice->client->service()->updateBalance($this->payment_amount*-1)->updatePaidToDate($this->payment_amount)->save(); - info("post client balance = {$this->invoice->client->balance}"); + // info("post client balance = {$this->invoice->client->balance}"); /* Update Pivot Record amount */ $this->payment->invoices->each(function ($inv) { @@ -55,8 +54,8 @@ class ApplyPayment extends AbstractService $this->invoice->fresh('client'); - info("1 end of apply payment method the client balance = {$this->invoice->client->balance}"); - + // info("1 end of apply payment method the client balance = {$this->invoice->client->balance}"); + if ($this->invoice->hasPartial()) { //is partial and amount is exactly the partial amount if ($this->invoice->partial == $this->payment_amount) { @@ -71,11 +70,11 @@ class ApplyPayment extends AbstractService } elseif ($this->payment_amount < $this->invoice->balance) { //partial invoice payment made $this->invoice->service()->clearPartial()->setStatus(Invoice::STATUS_PARTIAL)->updateBalance($this->payment_amount * -1); } - info("2 end of apply payment method the client balnace = {$this->invoice->client->balance}"); + // info("2 end of apply payment method the client balnace = {$this->invoice->client->balance}"); $this->invoice->service()->applyNumber()->save(); - info("3 end of apply payment method the client balnace = {$this->invoice->client->balance}"); + // info("3 end of apply payment method the client balnace = {$this->invoice->client->balance}"); return $this->invoice; } diff --git a/app/Services/Invoice/MarkSent.php b/app/Services/Invoice/MarkSent.php index 839f484f0dc6..ed8c8daaa7f1 100644 --- a/app/Services/Invoice/MarkSent.php +++ b/app/Services/Invoice/MarkSent.php @@ -37,9 +37,6 @@ class MarkSent extends AbstractService return $this->invoice; } -info("in mark sent"); -info($this->invoice->balance); - $this->invoice->markInvitationsSent(); $this->invoice->setReminder(); @@ -52,12 +49,8 @@ info($this->invoice->balance); ->updateBalance($this->invoice->amount) ->save(); -info($this->invoice->balance); - $this->client->service()->updateBalance($this->invoice->balance)->save(); -info($this->client->balance); - $this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance); event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars())); diff --git a/routes/client.php b/routes/client.php index b78370876d23..e66659765fc9 100644 --- a/routes/client.php +++ b/routes/client.php @@ -22,7 +22,7 @@ Route::post('view/{entity_type}/{invitation_key}/password', 'ClientPortal\Entity Route::get('tmp_pdf/{hash}', 'ClientPortal\TempRouteController@index')->name('tmp_pdf'); Route::get('client/key_login/{contact_key}', 'ClientPortal\ContactHashLoginController@login')->name('client.contact_login')->middleware(['contact_key_login']); -Route::get('documents/{contact_key}/{document}/download', 'ClientPortal\DocumentController@publicDownload')->name('documents.public_download'); +Route::get('documents/{document_hash}', 'ClientPortal\DocumentController@publicDownload')->name('documents.public_download'); //todo implement domain DB Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () { From 0f86b3ec21e9387ad026696b95fdf3650ad69e62 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Dec 2020 21:33:30 +1100 Subject: [PATCH 17/87] Fixes --- app/Exceptions/Handler.php | 3 ++- app/Jobs/Entity/CreateEntityPdf.php | 5 +++++ app/Jobs/Util/Import.php | 20 ++++++++------------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 1f71590459a8..cc6290e86a4a 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -67,7 +67,7 @@ class Handler extends ExceptionHandler * @throws Throwable */ public function report(Throwable $exception) - { + {info("errrrrrrrrrrrrrrrrrr"); if (! Schema::hasTable('accounts')) { info('account table not found'); return; @@ -101,6 +101,7 @@ class Handler extends ExceptionHandler private function validException($exception) { + info("valid exception = " .$exception->getMessage()); if(strpos($exception->getMessage(), 'file_put_contents') === TRUE) return FALSE; diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index a63b3590b13f..b815f483eebd 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -164,4 +164,9 @@ class CreateEntityPdf implements ShouldQueue return $file_path; } + + public function failed(\Exception $exception) + { + + } } diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index b3b30d3c724c..e8aea5395052 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -1048,13 +1048,11 @@ class Import implements ShouldQueue $cgt = ClientGatewayToken::Create($modified); - $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id; + $key = "client_gateway_tokens_{$resource['id']}"; - $this->ids['client_gateway_tokens'] = [ - "client_gateway_tokens_{$old_user_key}" => [ - 'old' => $resource['id'], - 'new' => $cgt->id, - ], + $this->ids['client_gateway_tokens'][$key] = [ + 'old' => $resource['id'], + 'new' => $cgt->id, ]; } @@ -1079,13 +1077,11 @@ class Import implements ShouldQueue $task_status = TaskStatus::Create($modified); - $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id; + $key = "task_statuses_{$resource['id']}"; - $this->ids['task_statuses'] = [ - "task_statuses_{$old_user_key}" => [ - 'old' => $resource['id'], - 'new' => $task_status->id, - ], + $this->ids['task_statuses'][$key] = [ + 'old' => $resource['id'], + 'new' => $task_status->id, ]; } From 2c4aaa2131b460baf1030b36e15cc461721f54d7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 07:37:29 +1100 Subject: [PATCH 18/87] Fixes for sentry reporting --- app/Events/Product/ProductWasArchived.php | 1 + app/Exceptions/Handler.php | 15 ++++++--------- app/Jobs/Entity/CreateEntityPdf.php | 2 +- composer.lock | 12 ++++++------ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/app/Events/Product/ProductWasArchived.php b/app/Events/Product/ProductWasArchived.php index 14a54db71aaa..38ab2990c0bf 100644 --- a/app/Events/Product/ProductWasArchived.php +++ b/app/Events/Product/ProductWasArchived.php @@ -11,6 +11,7 @@ namespace App\Events\Product; +use App\Models\Company; use App\Models\Product; use Illuminate\Queue\SerializesModels; diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index cc6290e86a4a..690f572ea15f 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -67,7 +67,8 @@ class Handler extends ExceptionHandler * @throws Throwable */ public function report(Throwable $exception) - {info("errrrrrrrrrrrrrrrrrr"); + { + if (! Schema::hasTable('accounts')) { info('account table not found'); return; @@ -90,8 +91,6 @@ class Handler extends ExceptionHandler } }); -// app('sentry')->setRelease(config('ninja.app_version')); - if($this->validException($exception)) app('sentry')->captureException($exception); } @@ -101,17 +100,15 @@ class Handler extends ExceptionHandler private function validException($exception) { - info("valid exception = " .$exception->getMessage()); - if(strpos($exception->getMessage(), 'file_put_contents') === TRUE) + if(strpos($exception->getMessage(), 'file_put_contents') !== FALSE) return FALSE; - if(strpos($exception->getMessage(), 'Permission denied') === TRUE) - return FALSE; - - if(strpos($exception->getMessage(), 'flock()') === TRUE) + if(strpos($exception->getMessage(), 'Permission denied') !== FALSE) return FALSE; + if(strpos($exception->getMessage(), 'flock()') !== FALSE) + return FALSE; return TRUE; } diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index b815f483eebd..9b92d5316f47 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -167,6 +167,6 @@ class CreateEntityPdf implements ShouldQueue public function failed(\Exception $exception) { - + info("help!"); } } diff --git a/composer.lock b/composer.lock index a710907da364..578bffb04798 100644 --- a/composer.lock +++ b/composer.lock @@ -116,16 +116,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.168.2", + "version": "3.168.3", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "1d6a976da857d13b156bd63613ee086c13f6dc29" + "reference": "49ef1f905388c8185012c9651b80941b8f2a218d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1d6a976da857d13b156bd63613ee086c13f6dc29", - "reference": "1d6a976da857d13b156bd63613ee086c13f6dc29", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/49ef1f905388c8185012c9651b80941b8f2a218d", + "reference": "49ef1f905388c8185012c9651b80941b8f2a218d", "shasum": "" }, "require": { @@ -200,9 +200,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.168.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.168.3" }, - "time": "2020-12-10T19:35:18+00:00" + "time": "2020-12-11T19:12:18+00:00" }, { "name": "brick/math", From 8b808c97fa0acc362a93446c1adc8a55a094cec8 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 07:58:18 +1100 Subject: [PATCH 19/87] Fixes for expense currency not setting default --- app/Http/Requests/Expense/StoreExpenseRequest.php | 4 ++-- app/Repositories/ExpenseRepository.php | 1 + app/Transformers/ExpenseTransformer.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Http/Requests/Expense/StoreExpenseRequest.php b/app/Http/Requests/Expense/StoreExpenseRequest.php index e2b5aa3ff2ee..544fb576c3ea 100644 --- a/app/Http/Requests/Expense/StoreExpenseRequest.php +++ b/app/Http/Requests/Expense/StoreExpenseRequest.php @@ -58,8 +58,8 @@ class StoreExpenseRequest extends Request $input['category_id'] = $this->decodePrimaryKey($input['category_id']); } - if (! array_key_exists('currency_id', $input)) { - $input['currency_id'] = auth()->user()->company()->settings->currency_id; + if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) { + $input['currency_id'] = (string)auth()->user()->company()->settings->currency_id; } $this->replace($input); diff --git a/app/Repositories/ExpenseRepository.php b/app/Repositories/ExpenseRepository.php index e08a7b88cc5f..e5058c21ba62 100644 --- a/app/Repositories/ExpenseRepository.php +++ b/app/Repositories/ExpenseRepository.php @@ -33,6 +33,7 @@ class ExpenseRepository extends BaseRepository */ public function save(array $data, Expense $expense) : ?Expense { + $expense->fill($data); $expense->number = empty($expense->number) ? $this->getNextExpenseNumber($expense) : $expense->number; $expense->save(); diff --git a/app/Transformers/ExpenseTransformer.php b/app/Transformers/ExpenseTransformer.php index 2760fe9c0033..b7f3c5474815 100644 --- a/app/Transformers/ExpenseTransformer.php +++ b/app/Transformers/ExpenseTransformer.php @@ -59,7 +59,7 @@ class ExpenseTransformer extends EntityTransformer 'bank_id' => (string) $expense->bank_id ?: '', 'invoice_currency_id' => (string) $expense->invoice_currency_id ?: '', 'expense_currency_id' => '', //todo remove redundant in 5.0.25 - 'currency_id' => (string) $expense->expense_currency_id ?: '', + 'currency_id' => (string) $expense->currency_id ?: '', 'category_id' => $this->encodePrimaryKey($expense->category_id), 'payment_type_id' => (string) $expense->payment_type_id ?: '', 'recurring_expense_id' => (string) $expense->recurring_expense_id ?: '', From d115609d3c3a55448acb952d7b124455632154d5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 15:59:15 +1100 Subject: [PATCH 20/87] Import | Exports --- app/Export/CSV/InvoiceExport.php | 17 +++++++ app/Http/Controllers/ImportController.php | 50 ++++++++++++++++++- app/Import/Definitions/InvoiceMap.php | 58 +++++++++++++++++++++++ 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 app/Export/CSV/InvoiceExport.php create mode 100644 app/Import/Definitions/InvoiceMap.php diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php new file mode 100644 index 000000000000..a0beec29c821 --- /dev/null +++ b/app/Export/CSV/InvoiceExport.php @@ -0,0 +1,17 @@ + 'number', + 1 => 'user_id', + 2 => 'amount', + 3 => 'balance', + 4 => 'client_id', + 5 => 'status_id', + 6 => 'is_deleted', + 7 => 'number', + 8 => 'discount', + 9 => 'po_number', + 10 => 'date', + 11 => 'due_date', + 12 => 'terms', + 13 => 'public_notes', + 14 => 'private_notes', + 15 => 'uses_inclusive_taxes', + 16 => 'tax_name1', + 17 => 'tax_rate1', + 18 => 'tax_name2', + 19 => 'tax_rate2', + 20 => 'tax_name3', + 21 => 'tax_rate3', + 22 => 'is_amount_discount', + 23 => 'footer', + 24 => 'partial', + 25 => 'partial_due_date', + 26 => 'custom_value1', + 27 => 'custom_value2', + 28 => 'custom_value3', + 29 => 'custom_value4', + 30 => 'custom_surcharge1', + 31 => 'custom_surcharge2', + 32 => 'custom_surcharge3', + 33 => 'custom_surcharge4', + 34 => 'exchange_rate', + 35 => 'line_items', + ]\InvoiceMap; use Illuminate\Http\Request; -use League\Csv\Reader; -use League\Csv\Statement; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; +use League\Csv\Reader; +use League\Csv\Statement; class ImportController extends Controller { @@ -82,6 +127,7 @@ class ImportController extends Controller $data['data'] = [ 'hash' => $hash, + 'available' => InvoiceMap::importable(), 'headers' => array_slice($csv_array, 0, 2) ]; diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php new file mode 100644 index 000000000000..a6780f86046a --- /dev/null +++ b/app/Import/Definitions/InvoiceMap.php @@ -0,0 +1,58 @@ + 'number', + 1 => 'user_id', + 2 => 'amount', + 3 => 'balance', + 4 => 'client_id', + 5 => 'status_id', + 6 => 'is_deleted', + 7 => 'number', + 8 => 'discount', + 9 => 'po_number', + 10 => 'date', + 11 => 'due_date', + 12 => 'terms', + 13 => 'public_notes', + 14 => 'private_notes', + 15 => 'uses_inclusive_taxes', + 16 => 'tax_name1', + 17 => 'tax_rate1', + 18 => 'tax_name2', + 19 => 'tax_rate2', + 20 => 'tax_name3', + 21 => 'tax_rate3', + 22 => 'is_amount_discount', + 23 => 'footer', + 24 => 'partial', + 25 => 'partial_due_date', + 26 => 'custom_value1', + 27 => 'custom_value2', + 28 => 'custom_value3', + 29 => 'custom_value4', + 30 => 'custom_surcharge1', + 31 => 'custom_surcharge2', + 32 => 'custom_surcharge3', + 33 => 'custom_surcharge4', + 34 => 'exchange_rate', + 35 => 'line_items', + ]; + } +} \ No newline at end of file From c0aa30ab587143fdf4805d1706233aa9325b78aa Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 16:03:23 +1100 Subject: [PATCH 21/87] Import|Export --- app/Export/CSV/InvoiceExport.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index a0beec29c821..9e7964a30469 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -11,7 +11,28 @@ namespace App\Export\CSV +use App\Models\Company; + class InvoiceExport { + private $company; + public function __construct(Company $company) + { + $this->company = $company; + } + + public function export() + { + $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'); + + } } \ No newline at end of file From 64b9f942993e006d7316a90291c9bae7dcf17129 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 21:43:07 +1100 Subject: [PATCH 22/87] Working on Import / Export --- app/Export/CSV/InvoiceExport.php | 17 ++-- app/Http/Controllers/ImportController.php | 48 +---------- app/Import/Definitions/InvoiceMap.php | 100 +++++++++++++++------- resources/lang/en/texts.php | 5 +- tests/Feature/Export/ExportCsvTest.php | 93 ++++++++++++++++++++ 5 files changed, 178 insertions(+), 85 deletions(-) create mode 100644 tests/Feature/Export/ExportCsvTest.php diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index 9e7964a30469..2f7b402afc97 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -9,9 +9,10 @@ * @license https://opensource.org/licenses/AAL */ -namespace App\Export\CSV +namespace App\Export\CSV; use App\Models\Company; +use Excel; class InvoiceExport { @@ -24,15 +25,15 @@ class InvoiceExport public function export() { - $fileName = 'test.csv'; + // $fileName = 'test.csv'; - $data = $this->company->invoices->get(); + // $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'); + // return Excel::create($fileName, function ($excel) use ($data) { + // $excel->sheet('', function ($sheet) use ($data) { + // $sheet->loadView('export', $data); + // }); + // })->download('csv'); } } \ No newline at end of file diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 8df74c74f19d..2d722ffb47bd 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -13,51 +13,7 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Http\Requests\Import\PreImportRequest; -use App\Import\Definitions - -class InvoiceMap -{ - - public static function importable() - { - return [ - 0 => 'number', - 1 => 'user_id', - 2 => 'amount', - 3 => 'balance', - 4 => 'client_id', - 5 => 'status_id', - 6 => 'is_deleted', - 7 => 'number', - 8 => 'discount', - 9 => 'po_number', - 10 => 'date', - 11 => 'due_date', - 12 => 'terms', - 13 => 'public_notes', - 14 => 'private_notes', - 15 => 'uses_inclusive_taxes', - 16 => 'tax_name1', - 17 => 'tax_rate1', - 18 => 'tax_name2', - 19 => 'tax_rate2', - 20 => 'tax_name3', - 21 => 'tax_rate3', - 22 => 'is_amount_discount', - 23 => 'footer', - 24 => 'partial', - 25 => 'partial_due_date', - 26 => 'custom_value1', - 27 => 'custom_value2', - 28 => 'custom_value3', - 29 => 'custom_value4', - 30 => 'custom_surcharge1', - 31 => 'custom_surcharge2', - 32 => 'custom_surcharge3', - 33 => 'custom_surcharge4', - 34 => 'exchange_rate', - 35 => 'line_items', - ]\InvoiceMap; +use App\Import\Definitions\Import\ImportMap; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; @@ -125,7 +81,7 @@ class ImportController extends Controller //parse CSV $csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname())); - $data['data'] = [ + $data = [ 'hash' => $hash, 'available' => InvoiceMap::importable(), 'headers' => array_slice($csv_array, 0, 2) diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php index a6780f86046a..8245bef32109 100644 --- a/app/Import/Definitions/InvoiceMap.php +++ b/app/Import/Definitions/InvoiceMap.php @@ -9,7 +9,7 @@ * @license https://opensource.org/licenses/AAL */ -namespace App\Import\Definitions +namespace App\Import\Definitions; class InvoiceMap { @@ -24,35 +24,75 @@ class InvoiceMap 4 => 'client_id', 5 => 'status_id', 6 => 'is_deleted', - 7 => 'number', - 8 => 'discount', - 9 => 'po_number', - 10 => 'date', - 11 => 'due_date', - 12 => 'terms', - 13 => 'public_notes', - 14 => 'private_notes', - 15 => 'uses_inclusive_taxes', - 16 => 'tax_name1', - 17 => 'tax_rate1', - 18 => 'tax_name2', - 19 => 'tax_rate2', - 20 => 'tax_name3', - 21 => 'tax_rate3', - 22 => 'is_amount_discount', - 23 => 'footer', - 24 => 'partial', - 25 => 'partial_due_date', - 26 => 'custom_value1', - 27 => 'custom_value2', - 28 => 'custom_value3', - 29 => 'custom_value4', - 30 => 'custom_surcharge1', - 31 => 'custom_surcharge2', - 32 => 'custom_surcharge3', - 33 => 'custom_surcharge4', - 34 => 'exchange_rate', - 35 => 'line_items', + 7 => 'discount', + 8 => 'po_number', + 9 => 'date', + 10 => 'due_date', + 11 => 'terms', + 12 => 'public_notes', + 13 => 'private_notes', + 14 => 'uses_inclusive_taxes', + 15 => 'tax_name1', + 16 => 'tax_rate1', + 17 => 'tax_name2', + 18 => 'tax_rate2', + 19 => 'tax_name3', + 20 => 'tax_rate3', + 21 => 'is_amount_discount', + 22 => 'footer', + 23 => 'partial', + 24 => 'partial_due_date', + 25 => 'custom_value1', + 26 => 'custom_value2', + 27 => 'custom_value3', + 28 => 'custom_value4', + 29 => 'custom_surcharge1', + 30 => 'custom_surcharge2', + 31 => 'custom_surcharge3', + 32 => 'custom_surcharge4', + 33 => 'exchange_rate', + 34 => 'line_items', + ]; + } + + public static function import_keys() + { + return [ + 0 => 'texts.invoice_number', + 1 => 'texts.user', + 2 => 'texts.amount', + 3 => 'texts.balance', + 4 => 'texts.client', + 5 => 'texts.status', + 6 => 'texts.deleted', + 7 => 'texts.discount', + 8 => 'texts.po_number', + 9 => 'texts.date', + 10 => 'texts.due_date', + 11 => 'texts.terms', + 12 => 'texts.public_notes', + 13 => 'texts.private_notes', + 14 => 'texts.uses_inclusive_taxes', + 15 => 'texts.tax_name1', + 16 => 'texts.tax_rate', + 17 => 'texts.tax_name', + 18 => 'texts.tax_rate', + 19 => 'texts.tax_name', + 20 => 'texts.tax_rate', + 21 => 'texts.is_amount_discount', + 22 => 'texts.footer', + 23 => 'texts.partial', + 24 => 'texts.partial_due_date', + 25 => 'texts.custom_value1', + 26 => 'texts.custom_value2', + 27 => 'texts.custom_value3', + 28 => 'texts.custom_value4', + 29 => 'texts.surcharge', + 30 => 'texts.surcharge', + 31 => 'texts.surcharge', + 32 => 'texts.surcharge', + 33 => 'texts.exchange_rate', + 34 => 'texts.items', ]; } } \ No newline at end of file diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 8186f608f01d..3eef076b20d0 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3318,6 +3318,9 @@ return [ 'notification_invoice_reminder2_sent_subject' => 'Reminder 2 for Invoice :invoice was sent to :client', 'notification_invoice_reminder3_sent_subject' => 'Reminder 3 for Invoice :invoice was sent to :client', 'notification_invoice_reminder_endless_sent_subject' => 'Endless reminder for Invoice :invoice was sent to :client', - + 'assigned_user' => 'Assigned User', + 'custom_value3' => 'Custom Value', + 'custom_value4' => 'Custom Value', + 'inclusive_taxes' => 'Include taxes', ]; diff --git a/tests/Feature/Export/ExportCsvTest.php b/tests/Feature/Export/ExportCsvTest.php new file mode 100644 index 000000000000..2662b606358b --- /dev/null +++ b/tests/Feature/Export/ExportCsvTest.php @@ -0,0 +1,93 @@ +withoutMiddleware( + ThrottleRequests::class + ); + + // $this->faker = \Faker\Factory::create(); + + $this->makeTestData(); + + $this->withoutExceptionHandling(); + } + + public function testExportCsv() + { + $csv = Writer::createFromFileObject(new \SplTempFileObject()); + + $header_invoice = Invoice::take(10)->get()->toArray(); + $header_item = $header_invoice[0]['line_items'][0]; + unset($header_invoice[0]['line_items']); + + $header_invoice_keys = array_keys($header_invoice[0]); + $header_item_keys = array_keys((array)$header_item); + + $header_invoice_values = array_values($header_invoice[0]); + $header_item_values = array_values((array)$header_item); + + $merged_values = array_merge($header_invoice_values, (array)$header_item_values); + $merged_keys = array_merge($header_invoice_keys, (array)$header_item_keys); + + info(print_r( $merged_keys,1)); + info(print_r( $merged_values,1)); + + + foreach($merged_keys as &$key) { + $key = ctrans('texts.'.$key); + } + + $csv->insertOne($merged_keys); + + foreach(Invoice::take(10)->get() as $invoice){ + + foreach($invoice->line_items as $item) { + + unset($invoice->line_items); + + $csv->insertOne(array_merge($invoice->toArray(), (array)$item)); + + } + + + } + + Storage::put(base_path('invy.csv'), $csv->getContent()); + + } + +} \ No newline at end of file From 141f45f40200b11d774d56adacee3b7054c80d98 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 22:18:54 +1100 Subject: [PATCH 23/87] Minor fixes for currency in expenses --- app/Http/Controllers/ImportController.php | 1 + .../Requests/Expense/UpdateExpenseRequest.php | 4 ++ app/Import/Definitions/InvoiceMap.php | 72 ++++++++++--------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 2d722ffb47bd..e1f38b2690da 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -14,6 +14,7 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Http\Requests\Import\PreImportRequest; use App\Import\Definitions\Import\ImportMap; +use App\Import\Definitions\InvoiceMap; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; diff --git a/app/Http/Requests/Expense/UpdateExpenseRequest.php b/app/Http/Requests/Expense/UpdateExpenseRequest.php index 23cb149fdfbe..7e29f2fa811d 100644 --- a/app/Http/Requests/Expense/UpdateExpenseRequest.php +++ b/app/Http/Requests/Expense/UpdateExpenseRequest.php @@ -66,6 +66,10 @@ class UpdateExpenseRequest extends Request $input['category_id'] = $this->decodePrimaryKey($input['category_id']); } + if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) { + $input['currency_id'] = (string)auth()->user()->company()->settings->currency_id; + } + $this->replace($input); } } diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php index 8245bef32109..cf8dfdb8f82f 100644 --- a/app/Import/Definitions/InvoiceMap.php +++ b/app/Import/Definitions/InvoiceMap.php @@ -17,41 +17,43 @@ class InvoiceMap public static function importable() { return [ - 0 => 'number', - 1 => 'user_id', - 2 => 'amount', - 3 => 'balance', - 4 => 'client_id', - 5 => 'status_id', - 6 => 'is_deleted', - 7 => 'discount', - 8 => 'po_number', - 9 => 'date', - 10 => 'due_date', - 11 => 'terms', - 12 => 'public_notes', - 13 => 'private_notes', - 14 => 'uses_inclusive_taxes', - 15 => 'tax_name1', - 16 => 'tax_rate1', - 17 => 'tax_name2', - 18 => 'tax_rate2', - 19 => 'tax_name3', - 20 => 'tax_rate3', - 21 => 'is_amount_discount', - 22 => 'footer', - 23 => 'partial', - 24 => 'partial_due_date', - 25 => 'custom_value1', - 26 => 'custom_value2', - 27 => 'custom_value3', - 28 => 'custom_value4', - 29 => 'custom_surcharge1', - 30 => 'custom_surcharge2', - 31 => 'custom_surcharge3', - 32 => 'custom_surcharge4', - 33 => 'exchange_rate', - 34 => 'line_items', + 0 => 'invoice.number', + 1 => 'invoice.user_id', + 2 => 'invoice.amount', + 3 => 'invoice.balance', + 4 => 'invoice.client_id', + 5 => 'invoice.status_id', + 6 => 'invoice.is_deleted', + 7 => 'invoice.discount', + 8 => 'invoice.po_number', + 9 => 'invoice.date', + 10 => 'invoice.due_date', + 11 => 'invoice.terms', + 12 => 'invoice.public_notes', + 13 => 'invoice.private_notes', + 14 => 'invoice.uses_inclusive_taxes', + 15 => 'invoice.tax_name1', + 16 => 'invoice.tax_rate1', + 17 => 'invoice.tax_name2', + 18 => 'invoice.tax_rate2', + 19 => 'invoice.tax_name3', + 20 => 'invoice.tax_rate3', + 21 => 'invoice.is_amount_discount', + 22 => 'invoice.footer', + 23 => 'invoice.partial', + 24 => 'invoice.partial_due_date', + 25 => 'invoice.custom_value1', + 26 => 'invoice.custom_value2', + 27 => 'invoice.custom_value3', + 28 => 'invoice.custom_value4', + 29 => 'invoice.custom_surcharge1', + 30 => 'invoice.custom_surcharge2', + 31 => 'invoice.custom_surcharge3', + 32 => 'invoice.custom_surcharge4', + 33 => 'invoice.exchange_rate', + 34 => 'invoice.line_items', + 35 => 'client.name', + 36 => 'client.email', ]; } From fc47fb90de6df43b141fad23773b8d7e4d75ff26 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Dec 2020 22:51:45 +1100 Subject: [PATCH 24/87] Database migrations for task fields --- .../2020_12_14_114722_task_fields.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 database/migrations/2020_12_14_114722_task_fields.php diff --git a/database/migrations/2020_12_14_114722_task_fields.php b/database/migrations/2020_12_14_114722_task_fields.php new file mode 100644 index 000000000000..bcb861986bf0 --- /dev/null +++ b/database/migrations/2020_12_14_114722_task_fields.php @@ -0,0 +1,36 @@ +boolean('is_date_based')->default(false); + }); + + Schema::table('companies', function (Blueprint $table) { + $table->boolean('default_task_is_date_based')->default(false); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} From dcd6574b2d5ced2c82ff60369e6e88523ee2b914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 14 Dec 2020 17:23:04 +0100 Subject: [PATCH 25/87] Experimental PDF rendering: - Added experimental flag in ninja.php - Added experimental rendering in PdfMaker.php - Added dynamic $global-margin for 1cm/0cm based on PDF method --- app/Utils/HtmlEngine.php | 7 ++-- app/Utils/Traits/Pdf/PdfMaker.php | 10 +++++ composer.json | 1 + composer.lock | 47 ++++++++++++++++++++++- config/ninja.php | 4 +- resources/views/pdf-designs/bold.html | 1 + resources/views/pdf-designs/business.html | 2 +- resources/views/pdf-designs/clean.html | 2 +- resources/views/pdf-designs/creative.html | 2 +- resources/views/pdf-designs/elegant.html | 2 +- resources/views/pdf-designs/hipster.html | 2 +- resources/views/pdf-designs/plain.html | 6 +-- resources/views/pdf-designs/playful.html | 2 +- 13 files changed, 73 insertions(+), 15 deletions(-) diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 3841cda5f5e8..e86e503deec9 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -92,8 +92,7 @@ class HtmlEngine } $data = []; - $data['$global-margin'] = ['value' => 'm-8', 'label' => '']; - $data['$global-padding'] = ['value' => 'p-8', 'label' => '']; + $data['$global-margin'] = ['value' => config('ninja.experimental_pdf_engine') ? '0cm' : '1cm', 'label' => '']; $data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => '']; $data['$from'] = ['value' => '', 'label' => ctrans('texts.from')]; @@ -155,7 +154,7 @@ class HtmlEngine } else { $data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')]; } - + $data['$quote.balance_due'] = $data['$balance_due']; $data['$invoice.balance_due'] = $data['$balance_due']; $data['$balance_due'] = $data['$balance_due']; @@ -243,7 +242,7 @@ class HtmlEngine $data['$client.postal_city_state'] = &$data['$postal_city_state']; $data['$client.country'] = &$data['$country']; $data['$client.email'] = &$data['$email']; - + $data['$client.currency'] = ['value' => $this->client->currency()->code, 'label' => '']; $data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; diff --git a/app/Utils/Traits/Pdf/PdfMaker.php b/app/Utils/Traits/Pdf/PdfMaker.php index 25fd6ef59437..d7c23960e76c 100644 --- a/app/Utils/Traits/Pdf/PdfMaker.php +++ b/app/Utils/Traits/Pdf/PdfMaker.php @@ -11,6 +11,7 @@ namespace App\Utils\Traits\Pdf; +use Beganovich\ChromiumPdf\ChromiumPdf; use Spatie\Browsershot\Browsershot; trait PdfMaker @@ -26,6 +27,15 @@ trait PdfMaker */ public function makePdf($header, $footer, $html) { + if (config('ninja.experimental_pdf_engine')) { + $pdf = new ChromiumPdf(); + + return $pdf + ->setChromiumPath(config('ninja.experimental_pdf_engine_chromium_path')) + ->setHtml($html) + ->generate(); + } + $browser = Browsershot::html($html); if (config('ninja.system.node_path')) { diff --git a/composer.json b/composer.json index 852cc0ceb6e5..fdcd1945ef31 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "ext-json": "*", "asgrim/ofxparser": "^1.2", "authorizenet/authorizenet": "^2.0", + "beganovich/chromium-pdf": "dev-master", "checkout/checkout-sdk-php": "^1.0", "cleverit/ubl_invoice": "^1.3", "composer/composer": "^2", diff --git a/composer.lock b/composer.lock index 578bffb04798..f8f336f200ed 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "35318cb6b03b84487f53dc09f2262030", + "content-hash": "75cb7287f45830678381d8e27486cf4a", "packages": [ { "name": "asgrim/ofxparser", @@ -204,6 +204,50 @@ }, "time": "2020-12-11T19:12:18+00:00" }, + { + "name": "beganovich/chromium-pdf", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/beganovich/chromium-pdf.git", + "reference": "0f1641f0f8272b68aa4942307b85fba5596a90c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beganovich/chromium-pdf/zipball/0f1641f0f8272b68aa4942307b85fba5596a90c3", + "reference": "0f1641f0f8272b68aa4942307b85fba5596a90c3", + "shasum": "" + }, + "require": { + "php": "^7.3|^7.4|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Beganovich\\ChromiumPdf\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Benjamin Beganović", + "email": "k1pstabug@gmail.com" + } + ], + "description": "Generate PDFs using headless Chromium", + "support": { + "issues": "https://github.com/beganovich/chromium-pdf/issues", + "source": "https://github.com/beganovich/chromium-pdf/tree/master" + }, + "time": "2020-12-14T15:49:17+00:00" + }, { "name": "brick/math", "version": "0.9.1", @@ -13836,6 +13880,7 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { + "beganovich/chromium-pdf": 20, "webpatser/laravel-countries": 20 }, "prefer-stable": true, diff --git a/config/ninja.php b/config/ninja.php index af59f5edb060..6119bfb3365b 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -32,7 +32,7 @@ return [ 'phantomjs_secret' => env('PHANTOMJS_SECRET', false), 'phantomjs_pdf_generation' => env('PHANTOMJS_PDF_GENERATION', true), 'trusted_proxies' => env('TRUSTED_PROXIES', false), - + 'sentry_dsn' => env('SENTRY_LARAVEL_DSN', 'https://9b4e15e575214354a7d666489783904a@sentry.invoicing.co/6'), 'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller' @@ -135,4 +135,6 @@ return [ 'designs' => [ 'base_path' => resource_path('views/pdf-designs/'), ], + 'experimental_pdf_engine' => env('EXPERIMENTAL_PDF_ENGINE', false), + 'experimental_pdf_engine_chromium_path' => env('EXPERIMENTAL_PDF_ENGINE_CHROMIUM_PATH', null), ]; diff --git a/resources/views/pdf-designs/bold.html b/resources/views/pdf-designs/bold.html index 4090a44c163d..a3c4fd17847f 100644 --- a/resources/views/pdf-designs/bold.html +++ b/resources/views/pdf-designs/bold.html @@ -14,6 +14,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; + margin: "$global-margin"; } p { diff --git a/resources/views/pdf-designs/business.html b/resources/views/pdf-designs/business.html index ff23b04d46cc..f29891db96c3 100644 --- a/resources/views/pdf-designs/business.html +++ b/resources/views/pdf-designs/business.html @@ -12,7 +12,7 @@ } @page { - margin: 1cm; + margin: "$global-margin"; } p { diff --git a/resources/views/pdf-designs/clean.html b/resources/views/pdf-designs/clean.html index 9bf61d599ac8..28cfeabcaf1f 100644 --- a/resources/views/pdf-designs/clean.html +++ b/resources/views/pdf-designs/clean.html @@ -9,7 +9,7 @@ -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; font-size: "$font_size"; - margin: 1cm; + margin: "$global-margin"; } p { diff --git a/resources/views/pdf-designs/creative.html b/resources/views/pdf-designs/creative.html index 03e3489dcf08..5aa384ccae97 100644 --- a/resources/views/pdf-designs/creative.html +++ b/resources/views/pdf-designs/creative.html @@ -30,7 +30,7 @@ } body { - margin: 2rem; + margin: "$global-margin"; } .header-wrapper { diff --git a/resources/views/pdf-designs/elegant.html b/resources/views/pdf-designs/elegant.html index 35342cfa65be..7686f5f22547 100644 --- a/resources/views/pdf-designs/elegant.html +++ b/resources/views/pdf-designs/elegant.html @@ -17,7 +17,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: 1cm; + margin: "$global-margin"; } .company-logo-wrapper { diff --git a/resources/views/pdf-designs/hipster.html b/resources/views/pdf-designs/hipster.html index 8f482848189f..42b6322bff98 100644 --- a/resources/views/pdf-designs/hipster.html +++ b/resources/views/pdf-designs/hipster.html @@ -20,7 +20,7 @@ } @page { - margin: 1cm; + margin: "$global-margin"; } .header-wrapper { diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 6384395e8d06..c72398f9fc9a 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -13,7 +13,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: 1cm; + margin: "$global-margin"; } .header-wrapper { @@ -58,8 +58,8 @@ flex-direction: column; } - #product-table, - #delivery-note-table, + #product-table, + #delivery-note-table, #task-table { min-width: 100%; table-layout: fixed; diff --git a/resources/views/pdf-designs/playful.html b/resources/views/pdf-designs/playful.html index 95c9f3d2ac2c..96516134d99e 100644 --- a/resources/views/pdf-designs/playful.html +++ b/resources/views/pdf-designs/playful.html @@ -17,7 +17,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: 1cm; + margin: "$global-margin"; } .header-wrapper { From ed20f2c4bcfb23ba30f5d7351b6fba059207059c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Dec 2020 07:53:31 +1100 Subject: [PATCH 26/87] Null safety in translations --- app/Utils/Traits/ClientGroupSettingsSaver.php | 8 +++ app/Utils/Traits/CompanySettingsSaver.php | 8 +++ composer.lock | 49 ++++++++++--------- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/app/Utils/Traits/ClientGroupSettingsSaver.php b/app/Utils/Traits/ClientGroupSettingsSaver.php index 94b8c239ae0b..16845ca696aa 100644 --- a/app/Utils/Traits/ClientGroupSettingsSaver.php +++ b/app/Utils/Traits/ClientGroupSettingsSaver.php @@ -63,6 +63,14 @@ trait ClientGroupSettingsSaver $entity_settings->{$key} = $value; } + //this pass will handle any null values that are in the translations + foreach ($settings->translations as $key => $value) { + if (is_null($settings->translations[$key])) + $settings->translations[$key] = ''; + } + + $entity_settings->translations = $settings->translations; + $entity->settings = $entity_settings; $entity->save(); diff --git a/app/Utils/Traits/CompanySettingsSaver.php b/app/Utils/Traits/CompanySettingsSaver.php index b096baaeb6a4..04443461cf28 100644 --- a/app/Utils/Traits/CompanySettingsSaver.php +++ b/app/Utils/Traits/CompanySettingsSaver.php @@ -58,6 +58,14 @@ trait CompanySettingsSaver } } + //this pass will handle any null values that are in the translations + foreach ($settings->translations as $key => $value) { + if (is_null($settings->translations[$key])) + $settings->translations[$key] = ''; + } + + $company_settings->translations = $settings->translations; + $entity->settings = $company_settings; $entity->save(); diff --git a/composer.lock b/composer.lock index 578bffb04798..3f3672951596 100644 --- a/composer.lock +++ b/composer.lock @@ -116,16 +116,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.168.3", + "version": "3.169.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "49ef1f905388c8185012c9651b80941b8f2a218d" + "reference": "d15a231355e4435fc33bab83df075ec31edd0a9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/49ef1f905388c8185012c9651b80941b8f2a218d", - "reference": "49ef1f905388c8185012c9651b80941b8f2a218d", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d15a231355e4435fc33bab83df075ec31edd0a9b", + "reference": "d15a231355e4435fc33bab83df075ec31edd0a9b", "shasum": "" }, "require": { @@ -200,9 +200,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.168.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.169.0" }, - "time": "2020-12-11T19:12:18+00:00" + "time": "2020-12-14T19:12:33+00:00" }, { "name": "brick/math", @@ -4019,16 +4019,16 @@ }, { "name": "monolog/monolog", - "version": "2.1.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5" + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9eee5cec93dfb313a38b6b288741e84e53f02d5", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "shasum": "" }, "require": { @@ -4041,16 +4041,17 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^6.0", + "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", - "php-parallel-lint/php-parallel-lint": "^1.0", "phpspec/prophecy": "^1.6.1", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <3.0", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { @@ -4070,7 +4071,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-main": "2.x-dev" } }, "autoload": { @@ -4086,11 +4087,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -4098,7 +4099,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.1.1" + "source": "https://github.com/Seldaek/monolog/tree/2.2.0" }, "funding": [ { @@ -4110,7 +4111,7 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:41:23+00:00" + "time": "2020-12-14T13:15:25+00:00" }, { "name": "mtdowling/jmespath.php", @@ -11469,16 +11470,16 @@ }, { "name": "phar-io/version", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae" + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/726c026815142e4f8677b7cb7f2249c9ffb7ecae", - "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae", + "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", "shasum": "" }, "require": { @@ -11514,9 +11515,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.0.3" + "source": "https://github.com/phar-io/version/tree/3.0.4" }, - "time": "2020-11-30T09:21:21+00:00" + "time": "2020-12-13T23:18:30+00:00" }, { "name": "php-cs-fixer/diff", From 864892a7d2b31852037216d11366757c668d4996 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Dec 2020 08:52:14 +1100 Subject: [PATCH 27/87] Migrate white label license --- app/Jobs/Util/Import.php | 8 ++++++++ app/Models/Company.php | 1 + app/Models/Task.php | 1 + app/Transformers/CompanyTransformer.php | 1 + app/Transformers/TaskTransformer.php | 1 + 5 files changed, 12 insertions(+) diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index e8aea5395052..01976d36ffbf 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -104,6 +104,7 @@ class Import implements ShouldQueue * @var array */ private $available_imports = [ + 'account', 'company', 'users', 'payment_terms', @@ -225,6 +226,13 @@ class Import implements ShouldQueue }); } + private function processAccount(array $data) :void + { + $account = $this->company->account; + $account->fill($data); + $account->save(); + } + /** * @param array $data * @throws Exception diff --git a/app/Models/Company.php b/app/Models/Company.php index 1a00725cebf1..2f769887b229 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -79,6 +79,7 @@ class Company extends BaseModel 'invoice_task_timelog', 'auto_start_tasks', 'is_disabled', + 'default_task_is_date_based', ]; protected $hidden = [ diff --git a/app/Models/Task.php b/app/Models/Task.php index 39fd8127888c..d290bcadef8d 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -38,6 +38,7 @@ class Task extends BaseModel 'invoice_documents', 'rate', 'number', + 'is_date_based', ]; protected $touches = []; diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php index c2e21c9229a5..46eb495b7dd8 100644 --- a/app/Transformers/CompanyTransformer.php +++ b/app/Transformers/CompanyTransformer.php @@ -146,6 +146,7 @@ class CompanyTransformer extends EntityTransformer 'invoice_task_documents' => (bool) $company->invoice_task_documents, 'show_tasks_table' => (bool) $company->show_tasks_table, 'use_credits_payment' => 'always', //todo remove + 'default_task_is_date_based' => (bool)$company->default_task_is_date_based, ]; } diff --git a/app/Transformers/TaskTransformer.php b/app/Transformers/TaskTransformer.php index 427c7a86b222..3b3ea7309830 100644 --- a/app/Transformers/TaskTransformer.php +++ b/app/Transformers/TaskTransformer.php @@ -66,6 +66,7 @@ class TaskTransformer extends EntityTransformer 'custom_value4' => $task->custom_value4 ?: '', 'status_id' => $this->encodePrimaryKey($task->status_id) ?: '', 'status_sort_order' => (int) $task->status_sort_order, + 'is_date_based' => (bool) $task->is_date_based, ]; } } From 57ee54032f83489e262d11768ff7fbc45441b420 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Dec 2020 09:59:41 +1100 Subject: [PATCH 28/87] Import CSV --- app/Http/Controllers/ImportController.php | 8 ++++ app/Http/Requests/Import/ImportRequest.php | 37 +++++++++++++++++++ app/Http/Requests/Import/PreImportRequest.php | 4 +- app/Import/Definitions/InvoiceMap.php | 10 ++++- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 app/Http/Requests/Import/ImportRequest.php diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index e1f38b2690da..8d65b0e33d13 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -12,9 +12,11 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; +use App\Http\Requests\Import\ImportRequest; use App\Http\Requests\Import\PreImportRequest; use App\Import\Definitions\Import\ImportMap; use App\Import\Definitions\InvoiceMap; +use App\Jobs\Import\CSVImport; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; @@ -91,6 +93,12 @@ class ImportController extends Controller return response()->json($data); } + public function import(ImportRequest $request) + { + CSVImport::dispatch($request, auth()->user()->company()); + + return response()->json(['message' => 'Importing data, email will be sent on completion'], 200); + } private function getCsvData($csvfile) { diff --git a/app/Http/Requests/Import/ImportRequest.php b/app/Http/Requests/Import/ImportRequest.php new file mode 100644 index 000000000000..a1f92a0dc465 --- /dev/null +++ b/app/Http/Requests/Import/ImportRequest.php @@ -0,0 +1,37 @@ +user()->isAdmin(); + } + + public function rules() + { + + return [ + 'hash' => 'required', + 'entity_type' => 'required', + ]; + + } +} diff --git a/app/Http/Requests/Import/PreImportRequest.php b/app/Http/Requests/Import/PreImportRequest.php index fdfb162e20af..b0f76e5637ce 100644 --- a/app/Http/Requests/Import/PreImportRequest.php +++ b/app/Http/Requests/Import/PreImportRequest.php @@ -12,7 +12,6 @@ namespace App\Http\Requests\Import; use App\Http\Requests\Request; -use App\Models\GroupSetting; class PreImportRequest extends Request { @@ -30,7 +29,8 @@ class PreImportRequest extends Request { return [ - 'file' => 'required|file|mimes:csv,txt' + 'file' => 'required|file|mimes:csv,txt', + 'entity_type' => 'required', ]; } diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php index cf8dfdb8f82f..a2e05c0256ca 100644 --- a/app/Import/Definitions/InvoiceMap.php +++ b/app/Import/Definitions/InvoiceMap.php @@ -54,6 +54,9 @@ class InvoiceMap 34 => 'invoice.line_items', 35 => 'client.name', 36 => 'client.email', + 37 => 'payment.date', + 38 => 'payment.amount', + 39 => 'payment.transaction_reference', ]; } @@ -75,7 +78,7 @@ class InvoiceMap 12 => 'texts.public_notes', 13 => 'texts.private_notes', 14 => 'texts.uses_inclusive_taxes', - 15 => 'texts.tax_name1', + 15 => 'texts.tax_name', 16 => 'texts.tax_rate', 17 => 'texts.tax_name', 18 => 'texts.tax_rate', @@ -95,6 +98,11 @@ class InvoiceMap 32 => 'texts.surcharge', 33 => 'texts.exchange_rate', 34 => 'texts.items', + 35 => 'texts.client_name', + 36 => 'texts.email', + 37 => 'texts.payment_date', + 38 => 'texts.payment_amount', + 39 => 'texts.transaction_reference', ]; } } \ No newline at end of file From 5025949eaa0a48fa5baec2e0126f2bceb796ac15 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Dec 2020 15:31:49 +1100 Subject: [PATCH 29/87] CSV import --- app/Jobs/Import/CSVImport.php | 74 +++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 app/Jobs/Import/CSVImport.php diff --git a/app/Jobs/Import/CSVImport.php b/app/Jobs/Import/CSVImport.php new file mode 100644 index 000000000000..49657ce0d065 --- /dev/null +++ b/app/Jobs/Import/CSVImport.php @@ -0,0 +1,74 @@ +request = $request; + + $this->company = $company; + + $this->hash = $request->input('hash'); + + $this->entity_type = $request->input('entity_type'); + + $this->skip_headers = $request->input('skip_headers'); + } + + /** + * Execute the job. + * + * + * @return void + */ + public function handle() + { + MultiDB::setDb($this->company->db); + + } + + public function failed($exception) + { + + } + + private function getCsv() + { + $base64_encoded_csv = Cache::get($this->hash); + + return base64_decode($base64_encoded_csv); + } +} From 3c9a8fdd35decec1f0cd2c8b9888bf4baee94103 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Dec 2020 20:38:12 +1100 Subject: [PATCH 30/87] Fixes for query filters --- .env.example | 2 +- app/Filters/QueryFilters.php | 4 +- app/Import/Definitions/InvoiceMap.php | 160 +++++++++++++++----------- resources/lang/en/texts.php | 2 +- 4 files changed, 97 insertions(+), 71 deletions(-) diff --git a/.env.example b/.env.example index 19c98183f300..ab3a104fb6f4 100644 --- a/.env.example +++ b/.env.example @@ -26,7 +26,7 @@ BROADCAST_DRIVER=log LOG_CHANNEL=stack CACHE_DRIVER=file QUEUE_CONNECTION=database -SESSION_DRIVER=cookie +SESSION_DRIVER=file SESSION_LIFETIME=120 REDIS_HOST=127.0.0.1 diff --git a/app/Filters/QueryFilters.php b/app/Filters/QueryFilters.php index d1a16ffa1d21..e9370f56e49f 100644 --- a/app/Filters/QueryFilters.php +++ b/app/Filters/QueryFilters.php @@ -104,11 +104,11 @@ abstract class QueryFilters * @param string $value * @return stdClass */ - public function split($value) : stdClass + public function split($value) : \stdClass { $exploded_array = explode(':', $value); - $parts = new stdClass; + $parts = new \stdClass; $parts->value = $exploded_array[0]; $parts->operator = $this->operatorConvertor($exploded_array[1]); diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php index a2e05c0256ca..8a3c34a08539 100644 --- a/app/Import/Definitions/InvoiceMap.php +++ b/app/Import/Definitions/InvoiceMap.php @@ -22,41 +22,54 @@ class InvoiceMap 2 => 'invoice.amount', 3 => 'invoice.balance', 4 => 'invoice.client_id', - 5 => 'invoice.status_id', - 6 => 'invoice.is_deleted', - 7 => 'invoice.discount', - 8 => 'invoice.po_number', - 9 => 'invoice.date', - 10 => 'invoice.due_date', - 11 => 'invoice.terms', - 12 => 'invoice.public_notes', - 13 => 'invoice.private_notes', - 14 => 'invoice.uses_inclusive_taxes', - 15 => 'invoice.tax_name1', - 16 => 'invoice.tax_rate1', - 17 => 'invoice.tax_name2', - 18 => 'invoice.tax_rate2', - 19 => 'invoice.tax_name3', - 20 => 'invoice.tax_rate3', - 21 => 'invoice.is_amount_discount', - 22 => 'invoice.footer', - 23 => 'invoice.partial', - 24 => 'invoice.partial_due_date', - 25 => 'invoice.custom_value1', - 26 => 'invoice.custom_value2', - 27 => 'invoice.custom_value3', - 28 => 'invoice.custom_value4', - 29 => 'invoice.custom_surcharge1', - 30 => 'invoice.custom_surcharge2', - 31 => 'invoice.custom_surcharge3', - 32 => 'invoice.custom_surcharge4', - 33 => 'invoice.exchange_rate', - 34 => 'invoice.line_items', - 35 => 'client.name', - 36 => 'client.email', - 37 => 'payment.date', - 38 => 'payment.amount', - 39 => 'payment.transaction_reference', + 5 => 'invoice.discount', + 6 => 'invoice.po_number', + 7 => 'invoice.date', + 8 => 'invoice.due_date', + 9 => 'invoice.terms', + 10 => 'invoice.public_notes', + 11 => 'invoice.is_sent', + 12 => 'invoice.private_notes', + 13 => 'invoice.uses_inclusive_taxes', + 14 => 'invoice.tax_name1', + 15 => 'invoice.tax_rate1', + 16 => 'invoice.tax_name2', + 17 => 'invoice.tax_rate2', + 18 => 'invoice.tax_name3', + 19 => 'invoice.tax_rate3', + 20 => 'invoice.is_amount_discount', + 21 => 'invoice.footer', + 22 => 'invoice.partial', + 23 => 'invoice.partial_due_date', + 24 => 'invoice.custom_value1', + 25 => 'invoice.custom_value2', + 26 => 'invoice.custom_value3', + 27 => 'invoice.custom_value4', + 28 => 'invoice.custom_surcharge1', + 29 => 'invoice.custom_surcharge2', + 30 => 'invoice.custom_surcharge3', + 31 => 'invoice.custom_surcharge4', + 32 => 'invoice.exchange_rate', + 33 => 'payment.date', + 34 => 'payment.amount', + 35 => 'payment.transaction_reference', + 36 => 'item.quantity', + 37 => 'item.cost', + 38 => 'item.product_key', + 39 => 'item.notes', + 40 => 'item.discount', + 41 => 'item.is_amount_discount', + 42 => 'item.tax_name1', + 43 => 'item.tax_rate1', + 44 => 'item.tax_name2', + 45 => 'item.tax_rate2', + 46 => 'item.tax_name3', + 47 => 'item.tax_rate3', + 48 => 'item.custom_value1', + 49 => 'item.custom_value2', + 50 => 'item.custom_value3', + 51 => 'item.custom_value4', + 52 => 'item.type_id', ]; } @@ -68,41 +81,54 @@ class InvoiceMap 2 => 'texts.amount', 3 => 'texts.balance', 4 => 'texts.client', - 5 => 'texts.status', - 6 => 'texts.deleted', - 7 => 'texts.discount', - 8 => 'texts.po_number', - 9 => 'texts.date', - 10 => 'texts.due_date', - 11 => 'texts.terms', - 12 => 'texts.public_notes', - 13 => 'texts.private_notes', - 14 => 'texts.uses_inclusive_taxes', - 15 => 'texts.tax_name', - 16 => 'texts.tax_rate', - 17 => 'texts.tax_name', - 18 => 'texts.tax_rate', - 19 => 'texts.tax_name', - 20 => 'texts.tax_rate', - 21 => 'texts.is_amount_discount', - 22 => 'texts.footer', - 23 => 'texts.partial', - 24 => 'texts.partial_due_date', - 25 => 'texts.custom_value1', - 26 => 'texts.custom_value2', - 27 => 'texts.custom_value3', - 28 => 'texts.custom_value4', + 5 => 'texts.discount', + 6 => 'texts.po_number', + 7 => 'texts.date', + 8 => 'texts.due_date', + 9 => 'texts.terms', + 10 => 'texts.public_notes', + 11 => 'texts.sent', + 12 => 'texts.private_notes', + 13 => 'texts.uses_inclusive_taxes', + 14 => 'texts.tax_name', + 15 => 'texts.tax_rate', + 16 => 'texts.tax_name', + 17 => 'texts.tax_rate', + 18 => 'texts.tax_name', + 19 => 'texts.tax_rate', + 20 => 'texts.is_amount_discount', + 21 => 'texts.footer', + 22 => 'texts.partial', + 23 => 'texts.partial_due_date', + 24 => 'texts.custom_value1', + 25 => 'texts.custom_value2', + 26 => 'texts.custom_value3', + 27 => 'texts.custom_value4', + 28 => 'texts.surcharge', 29 => 'texts.surcharge', 30 => 'texts.surcharge', 31 => 'texts.surcharge', - 32 => 'texts.surcharge', - 33 => 'texts.exchange_rate', - 34 => 'texts.items', - 35 => 'texts.client_name', - 36 => 'texts.email', - 37 => 'texts.payment_date', - 38 => 'texts.payment_amount', - 39 => 'texts.transaction_reference', + 32 => 'texts.exchange_rate', + 33 => 'texts.payment_date', + 34 => 'texts.payment_amount', + 35 => 'texts.transaction_reference', + 36 => 'texts.quantity', + 37 => 'texts.cost', + 38 => 'texts.product_key', + 39 => 'texts.notes', + 40 => 'texts.discount', + 41 => 'texts.is_amount_discount', + 42 => 'texts.tax_name', + 43 => 'texts.tax_rate', + 44 => 'texts.tax_name', + 45 => 'texts.tax_rate', + 46 => 'texts.tax_name', + 47 => 'texts.tax_rate', + 48 => 'texts.custom_value', + 49 => 'texts.custom_value', + 50 => 'texts.custom_value', + 51 => 'texts.custom_value', + 52 => 'texts.type', ]; } } \ No newline at end of file diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 565053ca7601..56845222f440 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3325,5 +3325,5 @@ return [ 'custom_value3' => 'Custom Value', 'custom_value4' => 'Custom Value', 'inclusive_taxes' => 'Include taxes', - + 'sort_order' => 'Sort Order', ]; From 300e42278f7e81a35fa8b1792407979a45a477ad Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Dec 2020 20:44:22 +1100 Subject: [PATCH 31/87] Client filters by name --- app/Filters/ClientFilters.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/Filters/ClientFilters.php b/app/Filters/ClientFilters.php index e367708d17f5..90ab4859597f 100644 --- a/app/Filters/ClientFilters.php +++ b/app/Filters/ClientFilters.php @@ -22,6 +22,18 @@ use Illuminate\Support\Facades\Gate; */ class ClientFilters extends QueryFilters { + + /** + * Filter by name. + * + * @param string $name + * @return Builder + */ + public function name(string $name): Builder + { + return $this->builder->where('name', 'like', '%'.$name.'%'); + } + /** * Filter by balance. * From 7ccd10adf9caa2e56a33ec76de5646486d21e3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 15 Dec 2020 11:45:04 +0100 Subject: [PATCH 32/87] - Change $global-margin to $global_margin to keep consistency - Update designs accordingly - Update ChromiumPdf version - Apply php-cs-fixer --- app/Console/Commands/DemoMode.php | 2 - app/Import/Definitions/InvoiceMap.php | 235 +++++++++--------- app/Providers/EventServiceProvider.php | 4 +- app/Utils/HtmlEngine.php | 2 +- composer.lock | 8 +- .../2020_12_14_114722_task_fields.php | 2 - resources/views/pdf-designs/bold.html | 2 +- resources/views/pdf-designs/business.html | 2 +- resources/views/pdf-designs/clean.html | 2 +- resources/views/pdf-designs/creative.html | 2 +- resources/views/pdf-designs/elegant.html | 2 +- resources/views/pdf-designs/hipster.html | 2 +- resources/views/pdf-designs/plain.html | 2 +- resources/views/pdf-designs/playful.html | 2 +- tests/Feature/Export/ExportCsvTest.php | 26 +- tests/Feature/Import/ImportCsvTest.php | 6 +- 16 files changed, 140 insertions(+), 161 deletions(-) diff --git a/app/Console/Commands/DemoMode.php b/app/Console/Commands/DemoMode.php index b80c6c5fd138..260895736c98 100644 --- a/app/Console/Commands/DemoMode.php +++ b/app/Console/Commands/DemoMode.php @@ -259,7 +259,6 @@ class DemoMode extends Command $client = $company->clients->random(); $this->createProject($client, $u2->id); - } } @@ -468,7 +467,6 @@ class DemoMode extends Command } $invoice->save(); - } private function createCredit($client, $assigned_user_id = null) diff --git a/app/Import/Definitions/InvoiceMap.php b/app/Import/Definitions/InvoiceMap.php index 8a3c34a08539..bacab67ffc1b 100644 --- a/app/Import/Definitions/InvoiceMap.php +++ b/app/Import/Definitions/InvoiceMap.php @@ -13,122 +13,121 @@ namespace App\Import\Definitions; class InvoiceMap { + public static function importable() + { + return [ + 0 => 'invoice.number', + 1 => 'invoice.user_id', + 2 => 'invoice.amount', + 3 => 'invoice.balance', + 4 => 'invoice.client_id', + 5 => 'invoice.discount', + 6 => 'invoice.po_number', + 7 => 'invoice.date', + 8 => 'invoice.due_date', + 9 => 'invoice.terms', + 10 => 'invoice.public_notes', + 11 => 'invoice.is_sent', + 12 => 'invoice.private_notes', + 13 => 'invoice.uses_inclusive_taxes', + 14 => 'invoice.tax_name1', + 15 => 'invoice.tax_rate1', + 16 => 'invoice.tax_name2', + 17 => 'invoice.tax_rate2', + 18 => 'invoice.tax_name3', + 19 => 'invoice.tax_rate3', + 20 => 'invoice.is_amount_discount', + 21 => 'invoice.footer', + 22 => 'invoice.partial', + 23 => 'invoice.partial_due_date', + 24 => 'invoice.custom_value1', + 25 => 'invoice.custom_value2', + 26 => 'invoice.custom_value3', + 27 => 'invoice.custom_value4', + 28 => 'invoice.custom_surcharge1', + 29 => 'invoice.custom_surcharge2', + 30 => 'invoice.custom_surcharge3', + 31 => 'invoice.custom_surcharge4', + 32 => 'invoice.exchange_rate', + 33 => 'payment.date', + 34 => 'payment.amount', + 35 => 'payment.transaction_reference', + 36 => 'item.quantity', + 37 => 'item.cost', + 38 => 'item.product_key', + 39 => 'item.notes', + 40 => 'item.discount', + 41 => 'item.is_amount_discount', + 42 => 'item.tax_name1', + 43 => 'item.tax_rate1', + 44 => 'item.tax_name2', + 45 => 'item.tax_rate2', + 46 => 'item.tax_name3', + 47 => 'item.tax_rate3', + 48 => 'item.custom_value1', + 49 => 'item.custom_value2', + 50 => 'item.custom_value3', + 51 => 'item.custom_value4', + 52 => 'item.type_id', + ]; + } - public static function importable() - { - return [ - 0 => 'invoice.number', - 1 => 'invoice.user_id', - 2 => 'invoice.amount', - 3 => 'invoice.balance', - 4 => 'invoice.client_id', - 5 => 'invoice.discount', - 6 => 'invoice.po_number', - 7 => 'invoice.date', - 8 => 'invoice.due_date', - 9 => 'invoice.terms', - 10 => 'invoice.public_notes', - 11 => 'invoice.is_sent', - 12 => 'invoice.private_notes', - 13 => 'invoice.uses_inclusive_taxes', - 14 => 'invoice.tax_name1', - 15 => 'invoice.tax_rate1', - 16 => 'invoice.tax_name2', - 17 => 'invoice.tax_rate2', - 18 => 'invoice.tax_name3', - 19 => 'invoice.tax_rate3', - 20 => 'invoice.is_amount_discount', - 21 => 'invoice.footer', - 22 => 'invoice.partial', - 23 => 'invoice.partial_due_date', - 24 => 'invoice.custom_value1', - 25 => 'invoice.custom_value2', - 26 => 'invoice.custom_value3', - 27 => 'invoice.custom_value4', - 28 => 'invoice.custom_surcharge1', - 29 => 'invoice.custom_surcharge2', - 30 => 'invoice.custom_surcharge3', - 31 => 'invoice.custom_surcharge4', - 32 => 'invoice.exchange_rate', - 33 => 'payment.date', - 34 => 'payment.amount', - 35 => 'payment.transaction_reference', - 36 => 'item.quantity', - 37 => 'item.cost', - 38 => 'item.product_key', - 39 => 'item.notes', - 40 => 'item.discount', - 41 => 'item.is_amount_discount', - 42 => 'item.tax_name1', - 43 => 'item.tax_rate1', - 44 => 'item.tax_name2', - 45 => 'item.tax_rate2', - 46 => 'item.tax_name3', - 47 => 'item.tax_rate3', - 48 => 'item.custom_value1', - 49 => 'item.custom_value2', - 50 => 'item.custom_value3', - 51 => 'item.custom_value4', - 52 => 'item.type_id', - ]; - } - - public static function import_keys() - { - return [ - 0 => 'texts.invoice_number', - 1 => 'texts.user', - 2 => 'texts.amount', - 3 => 'texts.balance', - 4 => 'texts.client', - 5 => 'texts.discount', - 6 => 'texts.po_number', - 7 => 'texts.date', - 8 => 'texts.due_date', - 9 => 'texts.terms', - 10 => 'texts.public_notes', - 11 => 'texts.sent', - 12 => 'texts.private_notes', - 13 => 'texts.uses_inclusive_taxes', - 14 => 'texts.tax_name', - 15 => 'texts.tax_rate', - 16 => 'texts.tax_name', - 17 => 'texts.tax_rate', - 18 => 'texts.tax_name', - 19 => 'texts.tax_rate', - 20 => 'texts.is_amount_discount', - 21 => 'texts.footer', - 22 => 'texts.partial', - 23 => 'texts.partial_due_date', - 24 => 'texts.custom_value1', - 25 => 'texts.custom_value2', - 26 => 'texts.custom_value3', - 27 => 'texts.custom_value4', - 28 => 'texts.surcharge', - 29 => 'texts.surcharge', - 30 => 'texts.surcharge', - 31 => 'texts.surcharge', - 32 => 'texts.exchange_rate', - 33 => 'texts.payment_date', - 34 => 'texts.payment_amount', - 35 => 'texts.transaction_reference', - 36 => 'texts.quantity', - 37 => 'texts.cost', - 38 => 'texts.product_key', - 39 => 'texts.notes', - 40 => 'texts.discount', - 41 => 'texts.is_amount_discount', - 42 => 'texts.tax_name', - 43 => 'texts.tax_rate', - 44 => 'texts.tax_name', - 45 => 'texts.tax_rate', - 46 => 'texts.tax_name', - 47 => 'texts.tax_rate', - 48 => 'texts.custom_value', - 49 => 'texts.custom_value', - 50 => 'texts.custom_value', - 51 => 'texts.custom_value', - 52 => 'texts.type', - ]; - } -} \ No newline at end of file + public static function import_keys() + { + return [ + 0 => 'texts.invoice_number', + 1 => 'texts.user', + 2 => 'texts.amount', + 3 => 'texts.balance', + 4 => 'texts.client', + 5 => 'texts.discount', + 6 => 'texts.po_number', + 7 => 'texts.date', + 8 => 'texts.due_date', + 9 => 'texts.terms', + 10 => 'texts.public_notes', + 11 => 'texts.sent', + 12 => 'texts.private_notes', + 13 => 'texts.uses_inclusive_taxes', + 14 => 'texts.tax_name', + 15 => 'texts.tax_rate', + 16 => 'texts.tax_name', + 17 => 'texts.tax_rate', + 18 => 'texts.tax_name', + 19 => 'texts.tax_rate', + 20 => 'texts.is_amount_discount', + 21 => 'texts.footer', + 22 => 'texts.partial', + 23 => 'texts.partial_due_date', + 24 => 'texts.custom_value1', + 25 => 'texts.custom_value2', + 26 => 'texts.custom_value3', + 27 => 'texts.custom_value4', + 28 => 'texts.surcharge', + 29 => 'texts.surcharge', + 30 => 'texts.surcharge', + 31 => 'texts.surcharge', + 32 => 'texts.exchange_rate', + 33 => 'texts.payment_date', + 34 => 'texts.payment_amount', + 35 => 'texts.transaction_reference', + 36 => 'texts.quantity', + 37 => 'texts.cost', + 38 => 'texts.product_key', + 39 => 'texts.notes', + 40 => 'texts.discount', + 41 => 'texts.is_amount_discount', + 42 => 'texts.tax_name', + 43 => 'texts.tax_rate', + 44 => 'texts.tax_name', + 45 => 'texts.tax_rate', + 46 => 'texts.tax_name', + 47 => 'texts.tax_rate', + 48 => 'texts.custom_value', + 49 => 'texts.custom_value', + 50 => 'texts.custom_value', + 51 => 'texts.custom_value', + 52 => 'texts.type', + ]; + } +} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 26f9853a63ce..9d3d4c696de1 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -122,8 +122,8 @@ use App\Listeners\Invoice\InvoiceArchivedActivity; use App\Listeners\Invoice\InvoiceCancelledActivity; use App\Listeners\Invoice\InvoiceDeletedActivity; use App\Listeners\Invoice\InvoiceEmailActivity; -use App\Listeners\Invoice\InvoiceEmailFailedActivity; use App\Listeners\Invoice\InvoiceEmailedNotification; +use App\Listeners\Invoice\InvoiceEmailFailedActivity; use App\Listeners\Invoice\InvoicePaidActivity; use App\Listeners\Invoice\InvoiceReminderEmailActivity; use App\Listeners\Invoice\InvoiceRestoredActivity; @@ -131,8 +131,8 @@ use App\Listeners\Invoice\InvoiceReversedActivity; use App\Listeners\Invoice\InvoiceViewedActivity; use App\Listeners\Invoice\UpdateInvoiceActivity; use App\Listeners\Misc\InvitationViewedListener; -use App\Listeners\Payment\PaymentEmailFailureActivity; use App\Listeners\Payment\PaymentEmailedActivity; +use App\Listeners\Payment\PaymentEmailFailureActivity; use App\Listeners\Payment\PaymentNotification; use App\Listeners\Payment\PaymentRestoredActivity; use App\Listeners\Quote\QuoteApprovedActivity; diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index e86e503deec9..12cbac3de004 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -92,7 +92,7 @@ class HtmlEngine } $data = []; - $data['$global-margin'] = ['value' => config('ninja.experimental_pdf_engine') ? '0cm' : '1cm', 'label' => '']; + $data['$global_margin'] = ['value' => config('ninja.experimental_pdf_engine') ? '0cm' : '1cm', 'label' => '']; $data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => '']; $data['$from'] = ['value' => '', 'label' => ctrans('texts.from')]; diff --git a/composer.lock b/composer.lock index 4724319c9982..a3e25bf94666 100644 --- a/composer.lock +++ b/composer.lock @@ -210,12 +210,12 @@ "source": { "type": "git", "url": "https://github.com/beganovich/chromium-pdf.git", - "reference": "0f1641f0f8272b68aa4942307b85fba5596a90c3" + "reference": "f6f32bb99616a1c1b7108250ccc438210134a99f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beganovich/chromium-pdf/zipball/0f1641f0f8272b68aa4942307b85fba5596a90c3", - "reference": "0f1641f0f8272b68aa4942307b85fba5596a90c3", + "url": "https://api.github.com/repos/beganovich/chromium-pdf/zipball/f6f32bb99616a1c1b7108250ccc438210134a99f", + "reference": "f6f32bb99616a1c1b7108250ccc438210134a99f", "shasum": "" }, "require": { @@ -246,7 +246,7 @@ "issues": "https://github.com/beganovich/chromium-pdf/issues", "source": "https://github.com/beganovich/chromium-pdf/tree/master" }, - "time": "2020-12-14T15:49:17+00:00" + "time": "2020-12-15T10:16:36+00:00" }, { "name": "brick/math", diff --git a/database/migrations/2020_12_14_114722_task_fields.php b/database/migrations/2020_12_14_114722_task_fields.php index bcb861986bf0..440330421bf0 100644 --- a/database/migrations/2020_12_14_114722_task_fields.php +++ b/database/migrations/2020_12_14_114722_task_fields.php @@ -13,7 +13,6 @@ class TaskFields extends Migration */ public function up() { - Schema::table('tasks', function (Blueprint $table) { $table->boolean('is_date_based')->default(false); }); @@ -21,7 +20,6 @@ class TaskFields extends Migration Schema::table('companies', function (Blueprint $table) { $table->boolean('default_task_is_date_based')->default(false); }); - } /** diff --git a/resources/views/pdf-designs/bold.html b/resources/views/pdf-designs/bold.html index a3c4fd17847f..348016d03fe3 100644 --- a/resources/views/pdf-designs/bold.html +++ b/resources/views/pdf-designs/bold.html @@ -14,7 +14,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: "$global-margin"; + margin: $global_margin; } p { diff --git a/resources/views/pdf-designs/business.html b/resources/views/pdf-designs/business.html index f29891db96c3..9d4206ca81cf 100644 --- a/resources/views/pdf-designs/business.html +++ b/resources/views/pdf-designs/business.html @@ -12,7 +12,7 @@ } @page { - margin: "$global-margin"; + margin: $global_margin; } p { diff --git a/resources/views/pdf-designs/clean.html b/resources/views/pdf-designs/clean.html index 28cfeabcaf1f..7c7a0524c33e 100644 --- a/resources/views/pdf-designs/clean.html +++ b/resources/views/pdf-designs/clean.html @@ -9,7 +9,7 @@ -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; font-size: "$font_size"; - margin: "$global-margin"; + margin: $global_margin; } p { diff --git a/resources/views/pdf-designs/creative.html b/resources/views/pdf-designs/creative.html index 5aa384ccae97..a3f3124a5a44 100644 --- a/resources/views/pdf-designs/creative.html +++ b/resources/views/pdf-designs/creative.html @@ -30,7 +30,7 @@ } body { - margin: "$global-margin"; + margin: $global_margin; } .header-wrapper { diff --git a/resources/views/pdf-designs/elegant.html b/resources/views/pdf-designs/elegant.html index 7686f5f22547..a33e8f1e3ffb 100644 --- a/resources/views/pdf-designs/elegant.html +++ b/resources/views/pdf-designs/elegant.html @@ -17,7 +17,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: "$global-margin"; + margin: $global_margin; } .company-logo-wrapper { diff --git a/resources/views/pdf-designs/hipster.html b/resources/views/pdf-designs/hipster.html index 42b6322bff98..3942a0eedba8 100644 --- a/resources/views/pdf-designs/hipster.html +++ b/resources/views/pdf-designs/hipster.html @@ -20,7 +20,7 @@ } @page { - margin: "$global-margin"; + margin: $global_margin; } .header-wrapper { diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index c72398f9fc9a..f9aeca6d44ac 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -13,7 +13,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: "$global-margin"; + margin: $global_margin; } .header-wrapper { diff --git a/resources/views/pdf-designs/playful.html b/resources/views/pdf-designs/playful.html index 96516134d99e..f9c1d5e752e9 100644 --- a/resources/views/pdf-designs/playful.html +++ b/resources/views/pdf-designs/playful.html @@ -17,7 +17,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-family: Arial, Helvetica, sans-serif; - margin: "$global-margin"; + margin: $global_margin; } .header-wrapper { diff --git a/tests/Feature/Export/ExportCsvTest.php b/tests/Feature/Export/ExportCsvTest.php index 2662b606358b..68ae53afc5ff 100644 --- a/tests/Feature/Export/ExportCsvTest.php +++ b/tests/Feature/Export/ExportCsvTest.php @@ -11,14 +11,9 @@ namespace Tests\Feature\Export; use App\Models\Invoice; -use App\Models\Product; use App\Utils\Traits\MakesHash; -use Illuminate\Database\Eloquent\Model; use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Support\Facades\Storage; -use Illuminate\Validation\ValidationException; -use League\Csv\Reader; -use League\Csv\Statement; use League\Csv\Writer; use Tests\MockAccountData; use Tests\TestCase; @@ -63,31 +58,24 @@ class ExportCsvTest extends TestCase $merged_values = array_merge($header_invoice_values, (array)$header_item_values); $merged_keys = array_merge($header_invoice_keys, (array)$header_item_keys); - info(print_r( $merged_keys,1)); - info(print_r( $merged_values,1)); + info(print_r($merged_keys, 1)); + info(print_r($merged_values, 1)); - foreach($merged_keys as &$key) { + foreach ($merged_keys as &$key) { $key = ctrans('texts.'.$key); } $csv->insertOne($merged_keys); - foreach(Invoice::take(10)->get() as $invoice){ - - foreach($invoice->line_items as $item) { - + foreach (Invoice::take(10)->get() as $invoice) { + foreach ($invoice->line_items as $item) { unset($invoice->line_items); $csv->insertOne(array_merge($invoice->toArray(), (array)$item)); - } - - } - Storage::put(base_path('invy.csv'), $csv->getContent()); - + Storage::put(base_path('invy.csv'), $csv->getContent()); } - -} \ No newline at end of file +} diff --git a/tests/Feature/Import/ImportCsvTest.php b/tests/Feature/Import/ImportCsvTest.php index 377d7fc1b22e..8d7fb687c662 100644 --- a/tests/Feature/Import/ImportCsvTest.php +++ b/tests/Feature/Import/ImportCsvTest.php @@ -10,11 +10,8 @@ */ namespace Tests\Feature\Import; -use App\Models\Product; use App\Utils\Traits\MakesHash; -use Illuminate\Database\Eloquent\Model; use Illuminate\Routing\Middleware\ThrottleRequests; -use Illuminate\Validation\ValidationException; use League\Csv\Reader; use League\Csv\Statement; use Tests\MockAccountData; @@ -54,7 +51,6 @@ class ImportCsvTest extends TestCase private function getCsvData($csvfile) { - if (! ini_get('auto_detect_line_endings')) { ini_set('auto_detect_line_endings', '1'); } @@ -79,4 +75,4 @@ class ImportCsvTest extends TestCase return $data; } -} \ No newline at end of file +} From 75b28e87999e4cfd589caa593b894c7dfbe53dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 15 Dec 2020 16:10:50 +0100 Subject: [PATCH 33/87] Update setup to show step by step before letting user submit everything --- .gitignore | 1 + public/js/setup/setup.js | 2 +- public/mix-manifest.json | 2 +- resources/js/setup/setup.js | 20 ++++++++++++++++---- resources/lang/en/texts.php | 10 ++++++---- resources/views/setup/_account.blade.php | 4 ++-- resources/views/setup/_application.blade.php | 9 ++++++--- resources/views/setup/_database.blade.php | 2 +- resources/views/setup/_mail.blade.php | 4 ++-- resources/views/setup/index.blade.php | 4 +++- 10 files changed, 39 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 04ca0e2494a5..05ad729598d1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ storage/migrations nbproject .php_cs.cache +public/test.pdf diff --git a/public/js/setup/setup.js b/public/js/setup/setup.js index 44d899fb911a..2cc739e45e11 100644 --- a/public/js/setup/setup.js +++ b/public/js/setup/setup.js @@ -1,2 +1,2 @@ /*! For license information please see setup.js.LICENSE.txt */ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=12)}({12:function(e,t,n){e.exports=n("tM+k")},"2SVd":function(e,t,n){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},"5oMp":function(e,t,n){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},"8oxB":function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function s(){throw new Error("clearTimeout has not been defined")}function a(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:s}catch(e){r=s}}();var u,c=[],f=!1,l=-1;function d(){f&&u&&(f=!1,u.length?c=u.concat(c):l=-1,c.length&&p())}function p(){if(!f){var e=a(d);f=!0;for(var t=c.length;t;){for(u=c,c=[];++l1)for(var n=1;n=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},r.forEach(["delete","get","head"],(function(e){u.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){u.headers[e]=r.merge(i)})),e.exports=u}).call(this,n("8oxB"))},LYNF:function(e,t,n){"use strict";var r=n("OH9c");e.exports=function(e,t,n,o,i){var s=new Error(e);return r(s,t,n,o,i)}},Lmem:function(e,t,n){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},MLWZ:function(e,t,n){"use strict";var r=n("xTJ+");function o(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}e.exports=function(e,t,n){if(!t)return e;var i;if(n)i=n(t);else if(r.isURLSearchParams(t))i=t.toString();else{var s=[];r.forEach(t,(function(e,t){null!=e&&(r.isArray(e)?t+="[]":e=[e],r.forEach(e,(function(e){r.isDate(e)?e=e.toISOString():r.isObject(e)&&(e=JSON.stringify(e)),s.push(o(t)+"="+o(e))})))})),i=s.join("&")}if(i){var a=e.indexOf("#");-1!==a&&(e=e.slice(0,a)),e+=(-1===e.indexOf("?")?"?":"&")+i}return e}},OH9c:function(e,t,n){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},OTTw:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=r.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");function o(e){var r=e;return t&&(n.setAttribute("href",r),r=n.href),n.setAttribute("href",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:"/"===n.pathname.charAt(0)?n.pathname:"/"+n.pathname}}return e=o(window.location.href),function(t){var n=r.isString(t)?o(t):t;return n.protocol===e.protocol&&n.host===e.host}}():function(){return!0}},"Rn+g":function(e,t,n){"use strict";var r=n("LYNF");e.exports=function(e,t,n){var o=n.config.validateStatus;!o||o(n.status)?e(n):t(r("Request failed with status code "+n.status,n.config,null,n.request,n))}},SntB:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=function(e,t){t=t||{};var n={},o=["url","method","params","data"],i=["headers","auth","proxy"],s=["baseURL","url","transformRequest","transformResponse","paramsSerializer","timeout","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","maxContentLength","validateStatus","maxRedirects","httpAgent","httpsAgent","cancelToken","socketPath"];r.forEach(o,(function(e){void 0!==t[e]&&(n[e]=t[e])})),r.forEach(i,(function(o){r.isObject(t[o])?n[o]=r.deepMerge(e[o],t[o]):void 0!==t[o]?n[o]=t[o]:r.isObject(e[o])?n[o]=r.deepMerge(e[o]):void 0!==e[o]&&(n[o]=e[o])})),r.forEach(s,(function(r){void 0!==t[r]?n[r]=t[r]:void 0!==e[r]&&(n[r]=e[r])}));var a=o.concat(i).concat(s),u=Object.keys(t).filter((function(e){return-1===a.indexOf(e)}));return r.forEach(u,(function(r){void 0!==t[r]?n[r]=t[r]:void 0!==e[r]&&(n[r]=e[r])})),n}},UnBK:function(e,t,n){"use strict";var r=n("xTJ+"),o=n("xAGQ"),i=n("Lmem"),s=n("JEQr");function a(e){e.cancelToken&&e.cancelToken.throwIfRequested()}e.exports=function(e){return a(e),e.headers=e.headers||{},e.data=o(e.data,e.headers,e.transformRequest),e.headers=r.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),r.forEach(["delete","get","head","post","put","patch","common"],(function(t){delete e.headers[t]})),(e.adapter||s.adapter)(e).then((function(t){return a(e),t.data=o(t.data,t.headers,e.transformResponse),t}),(function(t){return i(t)||(a(e),t&&t.response&&(t.response.data=o(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)}))}},endd:function(e,t,n){"use strict";function r(e){this.message=e}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,e.exports=r},eqyj:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=r.isStandardBrowserEnv()?{write:function(e,t,n,o,i,s){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(i)&&a.push("domain="+i),!0===s&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},g7np:function(e,t,n){"use strict";var r=n("2SVd"),o=n("5oMp");e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},"jfS+":function(e,t,n){"use strict";var r=n("endd");function o(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise((function(e){t=e}));var n=this;e((function(e){n.reason||(n.reason=new r(e),t(n.reason))}))}o.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},o.source=function(){var e;return{token:new o((function(t){e=t})),cancel:e}},e.exports=o},"tM+k":function(e,t,n){"use strict";n.r(t);var r=n("vDqi"),o=n.n(r);function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:null;e.classList.remove("alert-success"),e.innerText=t||"Oops, looks like something isn't correct!",e.classList.add("alert-failure")}},{key:"handle",value:function(){var e=this;this.checkDbButton.addEventListener("click",(function(){return e.handleDatabaseCheck()})),this.checkSmtpButton.addEventListener("click",(function(){return e.handleSmtpCheck()})),this.checkPdfButton.addEventListener("click",(function(){return e.handleTestPdfCheck()}))}}])&&i(t.prototype,n),r&&i(t,r),e}())).handle()},tQ2B:function(e,t,n){"use strict";var r=n("xTJ+"),o=n("Rn+g"),i=n("MLWZ"),s=n("g7np"),a=n("w0Vi"),u=n("OTTw"),c=n("LYNF");e.exports=function(e){return new Promise((function(t,f){var l=e.data,d=e.headers;r.isFormData(l)&&delete d["Content-Type"];var p=new XMLHttpRequest;if(e.auth){var h=e.auth.username||"",m=e.auth.password||"";d.Authorization="Basic "+btoa(h+":"+m)}var v=s(e.baseURL,e.url);if(p.open(e.method.toUpperCase(),i(v,e.params,e.paramsSerializer),!0),p.timeout=e.timeout,p.onreadystatechange=function(){if(p&&4===p.readyState&&(0!==p.status||p.responseURL&&0===p.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in p?a(p.getAllResponseHeaders()):null,r={data:e.responseType&&"text"!==e.responseType?p.response:p.responseText,status:p.status,statusText:p.statusText,headers:n,config:e,request:p};o(t,f,r),p=null}},p.onabort=function(){p&&(f(c("Request aborted",e,"ECONNABORTED",p)),p=null)},p.onerror=function(){f(c("Network Error",e,null,p)),p=null},p.ontimeout=function(){var t="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),f(c(t,e,"ECONNABORTED",p)),p=null},r.isStandardBrowserEnv()){var y=n("eqyj"),g=(e.withCredentials||u(v))&&e.xsrfCookieName?y.read(e.xsrfCookieName):void 0;g&&(d[e.xsrfHeaderName]=g)}if("setRequestHeader"in p&&r.forEach(d,(function(e,t){void 0===l&&"content-type"===t.toLowerCase()?delete d[t]:p.setRequestHeader(t,e)})),r.isUndefined(e.withCredentials)||(p.withCredentials=!!e.withCredentials),e.responseType)try{p.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&p.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&p.upload&&p.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then((function(e){p&&(p.abort(),f(e),p=null)})),void 0===l&&(l=null),p.send(l)}))}},vDqi:function(e,t,n){e.exports=n("zuR4")},w0Vi:function(e,t,n){"use strict";var r=n("xTJ+"),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,s={};return e?(r.forEach(e.split("\n"),(function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(s[t]&&o.indexOf(t)>=0)return;s[t]="set-cookie"===t?(s[t]?s[t]:[]).concat([n]):s[t]?s[t]+", "+n:n}})),s):s}},xAGQ:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=function(e,t,n){return r.forEach(n,(function(n){e=n(e,t)})),e}},"xTJ+":function(e,t,n){"use strict";var r=n("HSsa"),o=Object.prototype.toString;function i(e){return"[object Array]"===o.call(e)}function s(e){return void 0===e}function a(e){return null!==e&&"object"==typeof e}function u(e){return"[object Function]"===o.call(e)}function c(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),i(e))for(var n=0,r=e.length;n1)for(var n=1;n=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},r.forEach(["delete","get","head"],(function(e){u.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){u.headers[e]=r.merge(i)})),e.exports=u}).call(this,n("8oxB"))},LYNF:function(e,t,n){"use strict";var r=n("OH9c");e.exports=function(e,t,n,o,i){var s=new Error(e);return r(s,t,n,o,i)}},Lmem:function(e,t,n){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},MLWZ:function(e,t,n){"use strict";var r=n("xTJ+");function o(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}e.exports=function(e,t,n){if(!t)return e;var i;if(n)i=n(t);else if(r.isURLSearchParams(t))i=t.toString();else{var s=[];r.forEach(t,(function(e,t){null!=e&&(r.isArray(e)?t+="[]":e=[e],r.forEach(e,(function(e){r.isDate(e)?e=e.toISOString():r.isObject(e)&&(e=JSON.stringify(e)),s.push(o(t)+"="+o(e))})))})),i=s.join("&")}if(i){var a=e.indexOf("#");-1!==a&&(e=e.slice(0,a)),e+=(-1===e.indexOf("?")?"?":"&")+i}return e}},OH9c:function(e,t,n){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},OTTw:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=r.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");function o(e){var r=e;return t&&(n.setAttribute("href",r),r=n.href),n.setAttribute("href",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:"/"===n.pathname.charAt(0)?n.pathname:"/"+n.pathname}}return e=o(window.location.href),function(t){var n=r.isString(t)?o(t):t;return n.protocol===e.protocol&&n.host===e.host}}():function(){return!0}},"Rn+g":function(e,t,n){"use strict";var r=n("LYNF");e.exports=function(e,t,n){var o=n.config.validateStatus;!o||o(n.status)?e(n):t(r("Request failed with status code "+n.status,n.config,null,n.request,n))}},SntB:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=function(e,t){t=t||{};var n={},o=["url","method","params","data"],i=["headers","auth","proxy"],s=["baseURL","url","transformRequest","transformResponse","paramsSerializer","timeout","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","maxContentLength","validateStatus","maxRedirects","httpAgent","httpsAgent","cancelToken","socketPath"];r.forEach(o,(function(e){void 0!==t[e]&&(n[e]=t[e])})),r.forEach(i,(function(o){r.isObject(t[o])?n[o]=r.deepMerge(e[o],t[o]):void 0!==t[o]?n[o]=t[o]:r.isObject(e[o])?n[o]=r.deepMerge(e[o]):void 0!==e[o]&&(n[o]=e[o])})),r.forEach(s,(function(r){void 0!==t[r]?n[r]=t[r]:void 0!==e[r]&&(n[r]=e[r])}));var a=o.concat(i).concat(s),u=Object.keys(t).filter((function(e){return-1===a.indexOf(e)}));return r.forEach(u,(function(r){void 0!==t[r]?n[r]=t[r]:void 0!==e[r]&&(n[r]=e[r])})),n}},UnBK:function(e,t,n){"use strict";var r=n("xTJ+"),o=n("xAGQ"),i=n("Lmem"),s=n("JEQr");function a(e){e.cancelToken&&e.cancelToken.throwIfRequested()}e.exports=function(e){return a(e),e.headers=e.headers||{},e.data=o(e.data,e.headers,e.transformRequest),e.headers=r.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),r.forEach(["delete","get","head","post","put","patch","common"],(function(t){delete e.headers[t]})),(e.adapter||s.adapter)(e).then((function(t){return a(e),t.data=o(t.data,t.headers,e.transformResponse),t}),(function(t){return i(t)||(a(e),t&&t.response&&(t.response.data=o(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)}))}},endd:function(e,t,n){"use strict";function r(e){this.message=e}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,e.exports=r},eqyj:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=r.isStandardBrowserEnv()?{write:function(e,t,n,o,i,s){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(i)&&a.push("domain="+i),!0===s&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},g7np:function(e,t,n){"use strict";var r=n("2SVd"),o=n("5oMp");e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},"jfS+":function(e,t,n){"use strict";var r=n("endd");function o(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise((function(e){t=e}));var n=this;e((function(e){n.reason||(n.reason=new r(e),t(n.reason))}))}o.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},o.source=function(){var e;return{token:new o((function(t){e=t})),cancel:e}},e.exports=o},"tM+k":function(e,t,n){"use strict";n.r(t);var r=n("vDqi"),o=n.n(r);function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:null;e.classList.remove("alert-failure"),e.innerText="Success!",e.classList.add("alert-success"),t&&(document.getElementById(t).classList.remove("hidden"),document.getElementById(t).scrollIntoView({behavior:"smooth",block:"center"}))}},{key:"handleFailure",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e.classList.remove("alert-success"),e.innerText=t||"Oops, looks like something isn't correct!",e.classList.add("alert-failure")}},{key:"handle",value:function(){var e=this;this.checkDbButton.addEventListener("click",(function(){return e.handleDatabaseCheck()})),this.checkSmtpButton.addEventListener("click",(function(){return e.handleSmtpCheck()})),this.checkPdfButton.addEventListener("click",(function(){return e.handleTestPdfCheck()}))}}])&&i(t.prototype,n),r&&i(t,r),e}())).handle()},tQ2B:function(e,t,n){"use strict";var r=n("xTJ+"),o=n("Rn+g"),i=n("MLWZ"),s=n("g7np"),a=n("w0Vi"),u=n("OTTw"),c=n("LYNF");e.exports=function(e){return new Promise((function(t,f){var l=e.data,d=e.headers;r.isFormData(l)&&delete d["Content-Type"];var p=new XMLHttpRequest;if(e.auth){var h=e.auth.username||"",m=e.auth.password||"";d.Authorization="Basic "+btoa(h+":"+m)}var v=s(e.baseURL,e.url);if(p.open(e.method.toUpperCase(),i(v,e.params,e.paramsSerializer),!0),p.timeout=e.timeout,p.onreadystatechange=function(){if(p&&4===p.readyState&&(0!==p.status||p.responseURL&&0===p.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in p?a(p.getAllResponseHeaders()):null,r={data:e.responseType&&"text"!==e.responseType?p.response:p.responseText,status:p.status,statusText:p.statusText,headers:n,config:e,request:p};o(t,f,r),p=null}},p.onabort=function(){p&&(f(c("Request aborted",e,"ECONNABORTED",p)),p=null)},p.onerror=function(){f(c("Network Error",e,null,p)),p=null},p.ontimeout=function(){var t="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),f(c(t,e,"ECONNABORTED",p)),p=null},r.isStandardBrowserEnv()){var y=n("eqyj"),g=(e.withCredentials||u(v))&&e.xsrfCookieName?y.read(e.xsrfCookieName):void 0;g&&(d[e.xsrfHeaderName]=g)}if("setRequestHeader"in p&&r.forEach(d,(function(e,t){void 0===l&&"content-type"===t.toLowerCase()?delete d[t]:p.setRequestHeader(t,e)})),r.isUndefined(e.withCredentials)||(p.withCredentials=!!e.withCredentials),e.responseType)try{p.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&p.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&p.upload&&p.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then((function(e){p&&(p.abort(),f(e),p=null)})),void 0===l&&(l=null),p.send(l)}))}},vDqi:function(e,t,n){e.exports=n("zuR4")},w0Vi:function(e,t,n){"use strict";var r=n("xTJ+"),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,s={};return e?(r.forEach(e.split("\n"),(function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(s[t]&&o.indexOf(t)>=0)return;s[t]="set-cookie"===t?(s[t]?s[t]:[]).concat([n]):s[t]?s[t]+", "+n:n}})),s):s}},xAGQ:function(e,t,n){"use strict";var r=n("xTJ+");e.exports=function(e,t,n){return r.forEach(n,(function(n){e=n(e,t)})),e}},"xTJ+":function(e,t,n){"use strict";var r=n("HSsa"),o=Object.prototype.toString;function i(e){return"[object Array]"===o.call(e)}function s(e){return void 0===e}function a(e){return null!==e&&"object"==typeof e}function u(e){return"[object Function]"===o.call(e)}function c(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),i(e))for(var n=0,r=e.length;n this.handleSuccess(this.checkDbAlert)) + .then((response) => this.handleSuccess(this.checkDbAlert, 'mail-wrapper')) .catch((e) => this.handleFailure(this.checkDbAlert, e.response.data.message) ); @@ -55,6 +55,13 @@ class Setup { this.checkSmtpButton.disabled = true; + if (data.mail_driver === 'log') { + this.handleSuccess(this.checkSmtpAlert, 'account-wrapper'); + this.handleSuccess(this.checkSmtpAlert, 'submit-wrapper'); + + return this.checkSmtpButton.disabled = false; + } + Axios.post('/setup/check_mail', data) .then((response) => this.handleSuccess(this.checkSmtpAlert)) .catch((e) => @@ -70,9 +77,9 @@ class Setup { let win = window.open(response.data.url, '_blank'); win.focus(); - return this.handleSuccess(this.checkPdfAlert); + return this.handleSuccess(this.checkPdfAlert, 'database-wrapper'); } catch (error) { - this.handleSuccess(this.checkPdfAlert); + this.handleSuccess(this.checkPdfAlert, 'database-wrapper'); this.checkPdfAlert.textContent = `Success! You can preview test PDF here: ${response.data.url}`; } }) @@ -82,10 +89,15 @@ class Setup { }); } - handleSuccess(element) { + handleSuccess(element, nextStep = null) { element.classList.remove('alert-failure'); element.innerText = 'Success!'; element.classList.add('alert-success'); + + if (nextStep) { + document.getElementById(nextStep).classList.remove('hidden'); + document.getElementById(nextStep).scrollIntoView({behavior: 'smooth', block: 'center'}); + } } handleFailure(element, message = null) { diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 56845222f440..30348bc4604a 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -100,7 +100,7 @@ return [ 'powered_by' => 'Powered by', 'no_items' => 'No items', 'recurring_invoices' => 'Recurring Invoices', - 'recurring_help' => 'Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually. + 'recurring_help' => 'Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually. Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well, for example :MONTH-1. Examples of dynamic invoice variables:
    @@ -3277,7 +3277,7 @@ return [ 'under_payments_disabled' => 'Company doesn\'t support under payments.', 'over_payments_disabled' => 'Company doesn\'t support over payments.', - + 'paused' => 'Paused', 'saved_at' => 'Saved at :time', @@ -3292,7 +3292,7 @@ return [ 'pay_with_credit' => 'Pay with credit', 'payment_method_saving_failed' => 'Payment method can\'t be saved for future use.', - + 'pay_with' => 'Pay with', 'n/a' => 'N/A', @@ -3316,7 +3316,7 @@ return [ 'pay' => 'Pay', 'instructions' => 'Instructions', - + 'notification_invoice_reminder1_sent_subject' => 'Reminder 1 for Invoice :invoice was sent to :client', 'notification_invoice_reminder2_sent_subject' => 'Reminder 2 for Invoice :invoice was sent to :client', 'notification_invoice_reminder3_sent_subject' => 'Reminder 3 for Invoice :invoice was sent to :client', @@ -3326,4 +3326,6 @@ return [ 'custom_value4' => 'Custom Value', 'inclusive_taxes' => 'Include taxes', 'sort_order' => 'Sort Order', + + 'setup_steps_notice' => 'To proceed to next step, make sure you test each section.', ]; diff --git a/resources/views/setup/_account.blade.php b/resources/views/setup/_account.blade.php index 12b5a1dbdc55..435b439f4a3a 100644 --- a/resources/views/setup/_account.blade.php +++ b/resources/views/setup/_account.blade.php @@ -1,4 +1,4 @@ -
    +
- \ No newline at end of file + diff --git a/resources/views/setup/_application.blade.php b/resources/views/setup/_application.blade.php index 530e754e359a..e35de21a5e6e 100644 --- a/resources/views/setup/_application.blade.php +++ b/resources/views/setup/_application.blade.php @@ -22,7 +22,8 @@ {{ ctrans('texts.https') }}
- + {{ ctrans('texts.require') }} ({{ ctrans('texts.recommended_in_production') }})
@@ -42,9 +43,11 @@ {{ ctrans('texts.reports') }}
- + {{ ctrans('texts.send_fail_logs_to_our_server') }} - Read more about how we use this. + Read more + about how we use this.
diff --git a/resources/views/setup/_database.blade.php b/resources/views/setup/_database.blade.php index ad9508498605..0829e8974a26 100644 --- a/resources/views/setup/_database.blade.php +++ b/resources/views/setup/_database.blade.php @@ -1,4 +1,4 @@ -
+