From ee947ad6c6f0b1e36e6803b5cfd673672e1dc6cc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 07:30:02 +1000 Subject: [PATCH 1/7] Fixes for migrations --- .../2021_09_24_213858_add_bancontact_to_payment_types.php | 2 +- storage/app/public/.gitignore | 0 2 files changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 storage/app/public/.gitignore diff --git a/database/migrations/2021_09_24_213858_add_bancontact_to_payment_types.php b/database/migrations/2021_09_24_213858_add_bancontact_to_payment_types.php index a4daab9c68..74302b8d50 100644 --- a/database/migrations/2021_09_24_213858_add_bancontact_to_payment_types.php +++ b/database/migrations/2021_09_24_213858_add_bancontact_to_payment_types.php @@ -17,7 +17,7 @@ class AddBancontactToPaymentTypes extends Migration { $type = new PaymentType(); - $type->id = 35; + $type->id = 36; $type->name = 'Bancontact'; $type->gateway_type_id = GatewayType::BANCONTACT; diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore old mode 100644 new mode 100755 From f35ad6a5a35fd3135d399a683955888fc6db1fe5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 08:03:11 +1000 Subject: [PATCH 2/7] Inline downloads for file resources --- app/Filters/DocumentFilters.php | 8 ++++---- .../Controllers/ClientPortal/DocumentController.php | 7 ++++++- app/Models/GatewayType.php | 11 ----------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/app/Filters/DocumentFilters.php b/app/Filters/DocumentFilters.php index 125416d19d..50731fc7df 100644 --- a/app/Filters/DocumentFilters.php +++ b/app/Filters/DocumentFilters.php @@ -20,10 +20,10 @@ use Illuminate\Database\Eloquent\Builder; class DocumentFilters extends QueryFilters { - public function client_id(int $client_id) :Builder - { - return $this->builder->where('client_id', $client_id); - } + // public function client_id(int $client_id) :Builder + // { + // return $this->builder->where('client_id', $client_id); + // } /** * Filter based on search text. diff --git a/app/Http/Controllers/ClientPortal/DocumentController.php b/app/Http/Controllers/ClientPortal/DocumentController.php index f58001ac35..54d25ea99d 100644 --- a/app/Http/Controllers/ClientPortal/DocumentController.php +++ b/app/Http/Controllers/ClientPortal/DocumentController.php @@ -57,7 +57,12 @@ class DocumentController extends Controller { $document = Document::where('hash', $document_hash)->firstOrFail(); - return Storage::disk($document->disk)->download($document->url, $document->name); + $headers = []; + + if(request()->input('inline') == 'true') + $headers = array_merge($headers, ['Content-Disposition' => 'inline']); + + return Storage::disk($document->disk)->download($document->url, $document->name, $headers); } public function downloadMultiple(DownloadMultipleDocumentsRequest $request) diff --git a/app/Models/GatewayType.php b/app/Models/GatewayType.php index 6435db19b0..a7e06fb64c 100644 --- a/app/Models/GatewayType.php +++ b/app/Models/GatewayType.php @@ -43,37 +43,26 @@ class GatewayType extends StaticModel switch ($type) { case self::CREDIT_CARD: return ctrans('texts.credit_card'); - break; case self::BANK_TRANSFER: return ctrans('texts.bank_transfer'); - break; case self::PAYPAL: return ctrans('texts.paypal'); - break; case self::CRYPTO: return ctrans('texts.crypto'); - break; case self::CUSTOM: return ctrans('texts.custom'); - break; case self::ALIPAY: return ctrans('texts.alipay'); - break; case self::SOFORT: return ctrans('texts.sofort'); - break; case self::APPLE_PAY: return ctrans('texts.apple_pay'); - break; case self::SEPA: return ctrans('texts.sepa'); - break; case self::KBC: return ctrans('texts.kbc_cbc'); - break; case self::BANCONTACT: return ctrans('texts.bancontact'); - break; default: return 'Undefined.'; From 88c4fe0147a620ff94ecc7e37de0775306262aba Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 08:24:11 +1000 Subject: [PATCH 3/7] Recurring expense send date calculations --- app/Models/RecurringExpense.php | 73 +++++++++++++++++++ .../RecurringExpenseTransformer.php | 7 +- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/app/Models/RecurringExpense.php b/app/Models/RecurringExpense.php index 8682c0568f..986dd7eebb 100644 --- a/app/Models/RecurringExpense.php +++ b/app/Models/RecurringExpense.php @@ -164,4 +164,77 @@ class RecurringExpense extends BaseModel } } + public function recurringDates() + { + + /* Return early if nothing to send back! */ + if ($this->status_id == RecurringInvoice::STATUS_COMPLETED || + $this->remaining_cycles == 0 || + !$this->next_send_date) { + return []; + } + + /* Endless - lets send 10 back*/ + $iterations = $this->remaining_cycles; + + if ($this->remaining_cycles == -1) { + $iterations = 10; + } + + $data = []; + + if (!Carbon::parse($this->next_send_date)) { + return $data; + } + + $next_send_date = Carbon::parse($this->next_send_date)->copy(); + + for ($x=0; $x<$iterations; $x++) { + // we don't add the days... we calc the day of the month!! + $next_due_date = $this->nextDateByFrequency($next_send_date); + + $data[] = [ + 'send_date' => $next_send_date->format('Y-m-d'), + ]; + + } + + return $data; + } + + public function nextDateByFrequency($date) + { + $offset = $this->client->timezone_offset(); + + switch ($this->frequency_id) { + case RecurringInvoice::FREQUENCY_DAILY: + return $date->startOfDay()->addDay()->addSeconds($offset); + case RecurringInvoice::FREQUENCY_WEEKLY: + return $date->startOfDay()->addWeek()->addSeconds($offset); + case RecurringInvoice::FREQUENCY_TWO_WEEKS: + return $date->startOfDay()->addWeeks(2)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_FOUR_WEEKS: + return $date->startOfDay()->addWeeks(4)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_MONTHLY: + return $date->startOfDay()->addMonthNoOverflow()->addSeconds($offset); + case RecurringInvoice::FREQUENCY_TWO_MONTHS: + return $date->startOfDay()->addMonthsNoOverflow(2)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_THREE_MONTHS: + return $date->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_FOUR_MONTHS: + return $date->startOfDay()->addMonthsNoOverflow(4)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_SIX_MONTHS: + return $date->addMonthsNoOverflow(6)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_ANNUALLY: + return $date->startOfDay()->addYear()->addSeconds($offset); + case RecurringInvoice::FREQUENCY_TWO_YEARS: + return $date->startOfDay()->addYears(2)->addSeconds($offset); + case RecurringInvoice::FREQUENCY_THREE_YEARS: + return $date->startOfDay()->addYears(3)->addSeconds($offset); + default: + return null; + } + } + + } diff --git a/app/Transformers/RecurringExpenseTransformer.php b/app/Transformers/RecurringExpenseTransformer.php index 6457bb0007..6332e4535a 100644 --- a/app/Transformers/RecurringExpenseTransformer.php +++ b/app/Transformers/RecurringExpenseTransformer.php @@ -49,7 +49,7 @@ class RecurringExpenseTransformer extends EntityTransformer */ public function transform(RecurringExpense $recurring_expense) { - return [ + $data = [ 'id' => $this->encodePrimaryKey($recurring_expense->id), 'user_id' => $this->encodePrimaryKey($recurring_expense->user_id), 'assigned_user_id' => $this->encodePrimaryKey($recurring_expense->assigned_user_id), @@ -102,5 +102,10 @@ class RecurringExpenseTransformer extends EntityTransformer 'last_sent_date' => $recurring_expense->last_sent_date ?: '', 'next_send_date' => $recurring_expense->next_send_date ?: '', ]; + + if(request()->has('show_dates') && request()->query('show_dates') == 'true') + $data['recurring_dates'] = (array) $recurring_expense->recurringDates(); + + return $data; } } \ No newline at end of file From 8178cd4bac4f0c02951026b852eedef7bb6ec3bd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 08:27:17 +1000 Subject: [PATCH 4/7] Add triggered actions to update route of invoices --- app/Http/Controllers/InvoiceController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index dbbddde36c..72378bb0ec 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -397,7 +397,7 @@ class InvoiceController extends BaseController $invoice = $this->invoice_repo->save($request->all(), $invoice); - $invoice->service()->deletePdf(); + $invoice->service()->triggeredActions($request)->deletePdf(); event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); From d5e580b863beb730111c99b511efa5924307efbb Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 08:29:18 +1000 Subject: [PATCH 5/7] Add triggered actions to update route of quotes --- app/Http/Controllers/QuoteController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 843818fabc..867646fdc0 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -391,7 +391,9 @@ class QuoteController extends BaseController $quote = $this->quote_repo->save($request->all(), $quote); - $quote->service()->deletePdf(); + $quote->service() + ->triggeredActions($request) + ->deletePdf(); event(new QuoteWasUpdated($quote, $quote->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); From 768a8bebba422cd4afa783ec4cb0393b30b9ede6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 10:36:36 +1000 Subject: [PATCH 6/7] minor fixes for redundant code --- app/Models/RecurringExpense.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/RecurringExpense.php b/app/Models/RecurringExpense.php index 986dd7eebb..ef9f487907 100644 --- a/app/Models/RecurringExpense.php +++ b/app/Models/RecurringExpense.php @@ -191,7 +191,7 @@ class RecurringExpense extends BaseModel for ($x=0; $x<$iterations; $x++) { // we don't add the days... we calc the day of the month!! - $next_due_date = $this->nextDateByFrequency($next_send_date); + $this->nextDateByFrequency($next_send_date); $data[] = [ 'send_date' => $next_send_date->format('Y-m-d'), From 4443b13218f5b29d5853585c76703296bb0cee31 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 27 Sep 2021 11:40:17 +1000 Subject: [PATCH 7/7] Performance improvements for PDFs --- .../ClientPortal/InvitationController.php | 38 +++++++++++++++++-- app/Jobs/Entity/CreateEntityPdf.php | 3 -- app/Listeners/Credit/CreditViewedActivity.php | 2 + .../Invoice/InvoiceViewedActivity.php | 2 + app/Listeners/Quote/QuoteViewedActivity.php | 2 + 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/InvitationController.php b/app/Http/Controllers/ClientPortal/InvitationController.php index 1fbf37bedd..4a8f1fe4ee 100644 --- a/app/Http/Controllers/ClientPortal/InvitationController.php +++ b/app/Http/Controllers/ClientPortal/InvitationController.php @@ -16,6 +16,7 @@ use App\Events\Invoice\InvoiceWasViewed; use App\Events\Misc\InvitationWasViewed; use App\Events\Quote\QuoteWasViewed; use App\Http\Controllers\Controller; +use App\Jobs\Entity\CreateRawPdf; use App\Models\Client; use App\Models\ClientContact; use App\Models\Payment; @@ -106,15 +107,12 @@ class InvitationController extends Controller { switch ($entity_string) { case 'invoice': - $invitation->invoice->service()->markSent()->save(); event(new InvoiceWasViewed($invitation, $invitation->company, Ninja::eventVars())); break; case 'quote': - $invitation->quote->service()->markSent()->save(); event(new QuoteWasViewed($invitation, $invitation->company, Ninja::eventVars())); break; case 'credit': - $invitation->credit->service()->markSent()->save(); event(new CreditWasViewed($invitation, $invitation->company, Ninja::eventVars())); break; default: @@ -125,9 +123,43 @@ class InvitationController extends Controller public function routerForDownload(string $entity, string $invitation_key) { + + if(Ninja::isHosted()) + return $this->returnRawPdf($entity, $invitation_key); + return redirect('client/'.$entity.'/'.$invitation_key.'/download_pdf'); } + private function returnRawPdf(string $entity, string $invitation_key) + { + + $key = $entity.'_id'; + + $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; + + $invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key]) + ->with('contact.client') + ->firstOrFail(); + + if(!$invitation) + return response()->json(["message" => "no record found"], 400); + + $file_name = $invitation->{$entity}->numberFormatter().'.pdf'; + nlog($file_name); + + $file = CreateRawPdf::dispatchNow($invitation, $invitation->company->db); + + $headers = ['Content-Type' => 'application/pdf']; + + if(request()->input('inline') == 'true') + $headers = array_merge($headers, ['Content-Disposition' => 'inline']); + + return response()->streamDownload(function () use($file) { + echo $file; + }, $file_name, $headers); + + } + public function routerForIframe(string $entity, string $client_hash, string $invitation_key) { } diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index fe628350d0..bfa4e000c9 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -104,9 +104,6 @@ class CreateEntityPdf implements ShouldQueue /* Set customized translations _NOW_ */ $t->replace(Ninja::transformTranslations($this->entity->client->getMergedSettings())); - /*This line of code hurts... it deletes ALL $entity PDFs... this causes a race condition when trying to send an email*/ - // $this->entity->service()->deletePdf(); - if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') { return (new Phantom)->generate($this->invitation); } diff --git a/app/Listeners/Credit/CreditViewedActivity.php b/app/Listeners/Credit/CreditViewedActivity.php index 76bb71915d..bce928d8ef 100644 --- a/app/Listeners/Credit/CreditViewedActivity.php +++ b/app/Listeners/Credit/CreditViewedActivity.php @@ -41,6 +41,8 @@ class CreditViewedActivity implements ShouldQueue { MultiDB::setDb($event->company->db); + $event->invitation->credit->service()->markSent()->save(); + $fields = new stdClass; $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->user_id; diff --git a/app/Listeners/Invoice/InvoiceViewedActivity.php b/app/Listeners/Invoice/InvoiceViewedActivity.php index 6336734a91..c876b28fd6 100644 --- a/app/Listeners/Invoice/InvoiceViewedActivity.php +++ b/app/Listeners/Invoice/InvoiceViewedActivity.php @@ -45,6 +45,8 @@ class InvoiceViewedActivity implements ShouldQueue $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->invitation->invoice->user_id; + $event->invitation->invoice->service()->markSent()->save(); + $fields->user_id = $user_id; $fields->company_id = $event->invitation->company_id; $fields->activity_type_id = Activity::VIEW_INVOICE; diff --git a/app/Listeners/Quote/QuoteViewedActivity.php b/app/Listeners/Quote/QuoteViewedActivity.php index c20fb2ee87..8c7041f26a 100644 --- a/app/Listeners/Quote/QuoteViewedActivity.php +++ b/app/Listeners/Quote/QuoteViewedActivity.php @@ -41,6 +41,8 @@ class QuoteViewedActivity implements ShouldQueue { MultiDB::setDb($event->company->db); + $event->invitation->quote->service()->markSent()->save(); + $fields = new stdClass; $fields->user_id = $event->invitation->quote->user_id;