From edf2dfcc8045a692264dad1a44762ddb4df9e183 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 12 Jun 2021 19:40:28 +1000 Subject: [PATCH 01/19] Minor fixes --- app/Helpers/Mail/GmailTransport.php | 2 -- app/Jobs/Entity/CreateEntityPdf.php | 2 -- app/Models/Invoice.php | 2 +- app/Services/Invoice/InvoiceService.php | 13 +++++++++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/Helpers/Mail/GmailTransport.php b/app/Helpers/Mail/GmailTransport.php index 648bb043fd..9cc4147908 100644 --- a/app/Helpers/Mail/GmailTransport.php +++ b/app/Helpers/Mail/GmailTransport.php @@ -74,14 +74,12 @@ class GmailTransport extends Transport } - } $this->gmail->send(); $this->sendPerformed($message); - return $this->numberOfRecipients($message); } } diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 62b3e938d1..60b64ec244 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -102,8 +102,6 @@ class CreateEntityPdf implements ShouldQueue /* Set the locale*/ App::setLocale($this->contact->preferredLocale()); - // nlog($this->entity->client->getMergedSettings()); - /* Set customized translations _NOW_ */ $t->replace(Ninja::transformTranslations($this->entity->client->getMergedSettings())); diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 6febb5876f..f86191d99f 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -415,7 +415,7 @@ class Invoice extends BaseModel return Storage::disk(config('filesystems.default'))->{$type}($file_path); } elseif(Ninja::isHosted() && $portal){ - $file_path = CreateEntityPdf::dispatchNow($invitation,config('filesystems.default')); + $file_path = CreateEntityPdf::dispatchNow($invitation, config('filesystems.default')); return Storage::disk(config('filesystems.default'))->{$type}($file_path); } diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 54049fa002..a26e41d368 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -307,7 +307,7 @@ class InvoiceService public function deletePdf() { - //UnlinkFile::dispatchNow(config('filesystems.default'), $this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf'); + Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf'); if(Ninja::isHosted()) { @@ -351,8 +351,17 @@ class InvoiceService * PDF when it is updated etc. * @return InvoiceService */ - public function touchPdf() + public function touchPdf($force = false) { + if($force){ + + $this->invoice->invitations->each(function ($invitation) { + CreateEntityPdf::dispatchNow($invitation); + }); + + return $this; + } + $this->invoice->invitations->each(function ($invitation) { CreateEntityPdf::dispatch($invitation); }); From afdfddd7e9b97ed1338e8957f13410045cc19740 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 12 Jun 2021 21:50:01 +1000 Subject: [PATCH 02/19] Refactor for entity paths --- .../ClientPortal/InvoiceController.php | 5 +++-- app/Jobs/Entity/CreateEntityPdf.php | 8 +++---- app/Jobs/Invoice/ZipInvoices.php | 7 ++++-- app/Mail/Engine/CreditEmailEngine.php | 4 ++-- app/Mail/Engine/InvoiceEmailEngine.php | 4 ++-- app/Mail/Engine/PaymentEmailEngine.php | 2 +- app/Mail/Engine/QuoteEmailEngine.php | 4 ++-- app/Mail/MigrationCompleted.php | 3 --- app/Models/Client.php | 22 +++++++++++-------- app/Models/Credit.php | 2 +- app/Models/CreditInvitation.php | 4 ++-- app/Models/Invoice.php | 2 +- app/Models/InvoiceInvitation.php | 2 +- app/Models/Quote.php | 2 +- app/Models/QuoteInvitation.php | 4 ++-- app/Observers/InvoiceObserver.php | 5 ----- app/Services/Credit/CreditService.php | 6 ++++- app/Services/Credit/GetCreditPdf.php | 2 +- app/Services/Invoice/GenerateDeliveryNote.php | 5 +++-- app/Services/Invoice/GetInvoicePdf.php | 2 +- app/Services/Invoice/InvoiceService.php | 13 ++++++----- app/Services/Quote/GetQuotePdf.php | 2 +- app/Services/Quote/QuoteService.php | 6 ++++- app/Services/Recurring/GetInvoicePdf.php | 2 +- app/Services/Recurring/RecurringService.php | 8 ++++++- app/Utils/PhantomJS/Phantom.php | 8 +++---- 26 files changed, 76 insertions(+), 58 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/InvoiceController.php b/app/Http/Controllers/ClientPortal/InvoiceController.php index 0472578597..0fec89cc29 100644 --- a/app/Http/Controllers/ClientPortal/InvoiceController.php +++ b/app/Http/Controllers/ClientPortal/InvoiceController.php @@ -164,8 +164,9 @@ class InvoiceController extends Controller //if only 1 pdf, output to buffer for download if ($invoices->count() == 1) { - - $file = $invoices->first()->pdf_file_path(); + $invoice = $invoices->first(); + $invitation = $invoice->invitations->first(); + $file = $invoice->pdf_file_path($invitation); return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);; } diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 60b64ec244..4982c786a9 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -114,16 +114,16 @@ class CreateEntityPdf implements ShouldQueue $entity_design_id = ''; if ($this->entity instanceof Invoice) { - $path = $this->entity->client->invoice_filepath(); + $path = $this->entity->client->invoice_filepath($this->invitation); $entity_design_id = 'invoice_design_id'; } elseif ($this->entity instanceof Quote) { - $path = $this->entity->client->quote_filepath(); + $path = $this->entity->client->quote_filepath($this->invitation); $entity_design_id = 'quote_design_id'; } elseif ($this->entity instanceof Credit) { - $path = $this->entity->client->credit_filepath(); + $path = $this->entity->client->credit_filepath($this->invitation); $entity_design_id = 'credit_design_id'; } elseif ($this->entity instanceof RecurringInvoice) { - $path = $this->entity->client->recurring_invoice_filepath(); + $path = $this->entity->client->recurring_invoice_filepath($this->invitation); $entity_design_id = 'invoice_design_id'; } diff --git a/app/Jobs/Invoice/ZipInvoices.php b/app/Jobs/Invoice/ZipInvoices.php index 07a0544b63..fc66984ffc 100644 --- a/app/Jobs/Invoice/ZipInvoices.php +++ b/app/Jobs/Invoice/ZipInvoices.php @@ -78,13 +78,16 @@ class ZipInvoices implements ShouldQueue // create a new zipstream object $file_name = date('Y-m-d').'_'.str_replace(' ', '_', trans('texts.invoices')).'.zip'; - $path = $this->invoices->first()->client->invoice_filepath(); + $invoice = $this->invoices->first(); + $invitation = $invoice->invitations->first(); + + $path = $invoice->client->invoice_filepath($invitation); $zip = new ZipStream($file_name, $options); foreach ($this->invoices as $invoice) { //$zip->addFileFromPath(basename($invoice->pdf_file_path()), TempFile::path($invoice->pdf_file_path())); - $zip->addFileFromPath(basename($invoice->pdf_file_path()), $invoice->pdf_file_path()); + $zip->addFileFromPath(basename($invoice->pdf_file_path($invitation)), $invoice->pdf_file_path()); } $zip->finish(); diff --git a/app/Mail/Engine/CreditEmailEngine.php b/app/Mail/Engine/CreditEmailEngine.php index 07d5b60d3e..fae73019de 100644 --- a/app/Mail/Engine/CreditEmailEngine.php +++ b/app/Mail/Engine/CreditEmailEngine.php @@ -101,9 +101,9 @@ class CreditEmailEngine extends BaseEmailEngine if ($this->client->getSetting('pdf_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if(Ninja::isHosted()) - $this->setAttachments([$this->credit->pdf_file_path(null, 'url', true)]); + $this->setAttachments([$this->credit->pdf_file_path($this->invitation, 'url', true)]); else - $this->setAttachments([$this->credit->pdf_file_path()]); + $this->setAttachments([$this->credit->pdf_file_path($this->invitation)]); } diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index 09fe9b9c3e..59e1a4c0e2 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -112,9 +112,9 @@ class InvoiceEmailEngine extends BaseEmailEngine if ($this->client->getSetting('pdf_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if(Ninja::isHosted()) - $this->setAttachments([$this->invoice->pdf_file_path(null, 'url', true)]); + $this->setAttachments([$this->invoice->pdf_file_path($this->invitation, 'url', true)]); else - $this->setAttachments([$this->invoice->pdf_file_path()]); + $this->setAttachments([$this->invoice->pdf_file_path($this->invitation)]); // $this->setAttachments(['path' => $this->invoice->pdf_file_path(), 'name' => basename($this->invoice->pdf_file_path())]); diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index cc32c7e26f..010e047958 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -77,7 +77,7 @@ class PaymentEmailEngine extends BaseEmailEngine $this->payment->invoices->each(function ($invoice){ - $this->setAttachments([$invoice->pdf_file_path()]); + $this->setAttachments([$invoice->pdf_file_path($invoice->invitations->first())]); }); diff --git a/app/Mail/Engine/QuoteEmailEngine.php b/app/Mail/Engine/QuoteEmailEngine.php index 901a0c38db..978cff6cdc 100644 --- a/app/Mail/Engine/QuoteEmailEngine.php +++ b/app/Mail/Engine/QuoteEmailEngine.php @@ -103,9 +103,9 @@ class QuoteEmailEngine extends BaseEmailEngine if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if(Ninja::isHosted()) - $this->setAttachments([$this->quote->pdf_file_path(null, 'url', true)]); + $this->setAttachments([$this->quote->pdf_file_path($this->invitation, 'url', true)]); else - $this->setAttachments([$this->quote->pdf_file_path()]); + $this->setAttachments([$this->quote->pdf_file_path($this->invitation)]); } diff --git a/app/Mail/MigrationCompleted.php b/app/Mail/MigrationCompleted.php index 18d3d3636e..9181c1f268 100644 --- a/app/Mail/MigrationCompleted.php +++ b/app/Mail/MigrationCompleted.php @@ -41,9 +41,6 @@ class MigrationCompleted extends Mailable $result = $this->from(config('mail.from.address'), config('mail.from.name')) ->view('email.import.completed', $data); - // if($this->company->invoices->count() >=1) - // $result->attach($this->company->invoices->first()->pdf_file_path()); - return $result; } } diff --git a/app/Models/Client.php b/app/Models/Client.php index 732a70123c..e163e79066 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -638,24 +638,28 @@ class Client extends BaseModel implements HasLocalePreference })->first()->locale; } - public function invoice_filepath() - { - return $this->company->company_key.'/'.$this->client_hash.'/invoices/'; + public function invoice_filepath($invitation) + { + $contact_key = $invitation->contact->contact_key; + return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/invoices/'; } - public function quote_filepath() + public function quote_filepath($invitation) { - return $this->company->company_key.'/'.$this->client_hash.'/quotes/'; + $contact_key = $invitation->contact->contact_key; + return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/quotes/'; } - public function credit_filepath() + public function credit_filepath($invitation) { - return $this->company->company_key.'/'.$this->client_hash.'/credits/'; + $contact_key = $invitation->contact->contact_key; + return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/credits/'; } - public function recurring_invoice_filepath() + public function recurring_invoice_filepath($invitation) { - return $this->company->company_key.'/'.$this->client_hash.'/recurring_invoices/'; + $contact_key = $invitation->contact->contact_key; + return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/recurring_invoices/'; } public function company_filepath() diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 242dabd24d..3cd4028c6a 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -267,7 +267,7 @@ class Credit extends BaseModel if(!$invitation) throw new \Exception('Hard fail, could not create an invitation - is there a valid contact?'); - $file_path = $this->client->credit_filepath().$this->numberFormatter().'.pdf'; + $file_path = $this->client->credit_filepath($invitation).$this->numberFormatter().'.pdf'; if(Ninja::isHosted() && $portal && Storage::disk(config('filesystems.default'))->exists($file_path)){ return Storage::disk(config('filesystems.default'))->{$type}($file_path); diff --git a/app/Models/CreditInvitation.php b/app/Models/CreditInvitation.php index 2db1c13167..ffabc6b265 100644 --- a/app/Models/CreditInvitation.php +++ b/app/Models/CreditInvitation.php @@ -126,9 +126,9 @@ class CreditInvitation extends BaseModel public function pdf_file_path() { - $storage_path = Storage::url($this->credit->client->quote_filepath().$this->credit->numberFormatter().'.pdf'); + $storage_path = Storage::url($this->credit->client->quote_filepath($this).$this->credit->numberFormatter().'.pdf'); - if (! Storage::exists($this->credit->client->credit_filepath().$this->credit->numberFormatter().'.pdf')) { + if (! Storage::exists($this->credit->client->credit_filepath($this).$this->credit->numberFormatter().'.pdf')) { event(new CreditWasUpdated($this, $this->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); CreateEntityPdf::dispatchNow($this); } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index f86191d99f..5715f4823b 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -409,7 +409,7 @@ class Invoice extends BaseModel if(!$invitation) throw new \Exception('Hard fail, could not create an invitation - is there a valid contact?'); - $file_path = $this->client->invoice_filepath().$this->numberFormatter().'.pdf'; + $file_path = $this->client->invoice_filepath($invitation).$this->numberFormatter().'.pdf'; if(Ninja::isHosted() && $portal && Storage::disk(config('filesystems.default'))->exists($file_path)){ return Storage::disk(config('filesystems.default'))->{$type}($file_path); diff --git a/app/Models/InvoiceInvitation.php b/app/Models/InvoiceInvitation.php index 3fa1f4918c..1e55b60751 100644 --- a/app/Models/InvoiceInvitation.php +++ b/app/Models/InvoiceInvitation.php @@ -142,7 +142,7 @@ class InvoiceInvitation extends BaseModel { $storage_path = Storage::url($this->invoice->client->invoice_filepath().$this->invoice->numberFormatter().'.pdf'); - if (! Storage::exists($this->invoice->client->invoice_filepath().$this->invoice->numberFormatter().'.pdf')) { + if (! Storage::exists($this->invoice->client->invoice_filepath($this).$this->invoice->numberFormatter().'.pdf')) { event(new InvoiceWasUpdated($this->invoice, $this->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); CreateEntityPdf::dispatchNow($this); } diff --git a/app/Models/Quote.php b/app/Models/Quote.php index c7d3118dc7..dfe32b9e90 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -219,7 +219,7 @@ class Quote extends BaseModel if(!$invitation) throw new \Exception('Hard fail, could not create an invitation - is there a valid contact?'); - $file_path = $this->client->quote_filepath().$this->numberFormatter().'.pdf'; + $file_path = $this->client->quote_filepath($invitation).$this->numberFormatter().'.pdf'; if(Ninja::isHosted() && $portal && Storage::disk(config('filesystems.default'))->exists($file_path)){ return Storage::disk(config('filesystems.default'))->{$type}($file_path); diff --git a/app/Models/QuoteInvitation.php b/app/Models/QuoteInvitation.php index 901d0bc54e..c5159cfa28 100644 --- a/app/Models/QuoteInvitation.php +++ b/app/Models/QuoteInvitation.php @@ -130,9 +130,9 @@ class QuoteInvitation extends BaseModel public function pdf_file_path() { - $storage_path = Storage::url($this->quote->client->quote_filepath().$this->quote->numberFormatter().'.pdf'); + $storage_path = Storage::url($this->quote->client->quote_filepath($this).$this->quote->numberFormatter().'.pdf'); - if (! Storage::exists($this->quote->client->quote_filepath().$this->quote->numberFormatter().'.pdf')) { + if (! Storage::exists($this->quote->client->quote_filepath($this).$this->quote->numberFormatter().'.pdf')) { event(new QuoteWasUpdated($this->quote, $this->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); CreateEntityPdf::dispatchNow($this); } diff --git a/app/Observers/InvoiceObserver.php b/app/Observers/InvoiceObserver.php index b91436d2ed..fddcb6624b 100644 --- a/app/Observers/InvoiceObserver.php +++ b/app/Observers/InvoiceObserver.php @@ -51,11 +51,6 @@ class InvoiceObserver if ($subscriptions) { WebhookHandler::dispatch(Webhook::EVENT_UPDATE_INVOICE, $invoice, $invoice->company); } - - // if($invoice->isDirty('date') || $invoice->isDirty('due_date')) - // $invoice->service()->setReminder()->save(); - - // UnlinkFile::dispatchNow(config('filesystems.default'), $invoice->client->invoice_filepath() . $invoice->numberFormatter().'.pdf'); } diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index a07e572eb2..48073b5772 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -140,7 +140,11 @@ class CreditService public function deletePdf() { - UnlinkFile::dispatchNow(config('filesystems.default'), $this->credit->client->credit_filepath() . $this->credit->numberFormatter().'.pdf'); + $this->credit->invitations->each(function ($invitation){ + + UnlinkFile::dispatchNow(config('filesystems.default'), $this->credit->client->credit_filepath($invitation) . $this->credit->numberFormatter().'.pdf'); + + }); return $this; } diff --git a/app/Services/Credit/GetCreditPdf.php b/app/Services/Credit/GetCreditPdf.php index 9114ec5fdb..11acb7dfcb 100644 --- a/app/Services/Credit/GetCreditPdf.php +++ b/app/Services/Credit/GetCreditPdf.php @@ -37,7 +37,7 @@ class GetCreditPdf extends AbstractService $this->contact = $this->credit->client->primary_contact()->first(); } - $path = $this->credit->client->credit_filepath(); + $path = $this->credit->client->credit_filepath($this->invitation); $file_path = $path.$this->credit->numberFormatter().'.pdf'; diff --git a/app/Services/Invoice/GenerateDeliveryNote.php b/app/Services/Invoice/GenerateDeliveryNote.php index 4c8d681a73..e194b6d41d 100644 --- a/app/Services/Invoice/GenerateDeliveryNote.php +++ b/app/Services/Invoice/GenerateDeliveryNote.php @@ -60,14 +60,15 @@ class GenerateDeliveryNote ? $this->invoice->design_id : $this->decodePrimaryKey($this->invoice->client->getSetting('invoice_design_id')); - $file_path = sprintf('%s%s_delivery_note.pdf', $this->invoice->client->invoice_filepath(), $this->invoice->number); + $invitation = $this->invoice->invitations->first(); + $file_path = sprintf('%s%s_delivery_note.pdf', $this->invoice->client->invoice_filepath($invitation), $this->invoice->number); if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') { return (new Phantom)->generate($this->invoice->invitations->first()); } $design = Design::find($design_id); - $html = new HtmlEngine($this->invoice->invitations->first()); + $html = new HtmlEngine($invitation); if ($design->is_custom) { $options = ['custom_partials' => json_decode(json_encode($design->design), true)]; diff --git a/app/Services/Invoice/GetInvoicePdf.php b/app/Services/Invoice/GetInvoicePdf.php index 8d42aabfb6..535d70ddb7 100644 --- a/app/Services/Invoice/GetInvoicePdf.php +++ b/app/Services/Invoice/GetInvoicePdf.php @@ -35,7 +35,7 @@ class GetInvoicePdf extends AbstractService $invitation = $this->invoice->invitations->where('client_contact_id', $this->contact->id)->first(); - $path = $this->invoice->client->invoice_filepath(); + $path = $this->invoice->client->invoice_filepath($invitation); $file_path = $path.$this->invoice->numberFormatter().'.pdf'; diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index a26e41d368..8ac66ed6c7 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -307,12 +307,15 @@ class InvoiceService public function deletePdf() { + $this->invoice->invitations->each(function ($invitation){ - Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf'); - - if(Ninja::isHosted()) { - Storage::disk('public')->delete($this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf'); - } + Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf'); + + if(Ninja::isHosted()) { + Storage::disk('public')->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf'); + } + + }); return $this; } diff --git a/app/Services/Quote/GetQuotePdf.php b/app/Services/Quote/GetQuotePdf.php index 7990c81a98..a28a09a6b8 100644 --- a/app/Services/Quote/GetQuotePdf.php +++ b/app/Services/Quote/GetQuotePdf.php @@ -35,7 +35,7 @@ class GetQuotePdf extends AbstractService $invitation = $this->quote->invitations->where('client_contact_id', $this->contact->id)->first(); - $path = $this->quote->client->quote_filepath(); + $path = $this->quote->client->quote_filepath($invitation); $file_path = $path.$this->quote->numberFormatter().'.pdf'; diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index b768462082..76b007896b 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -178,7 +178,11 @@ class QuoteService public function deletePdf() { - UnlinkFile::dispatchNow(config('filesystems.default'), $this->quote->client->quote_filepath() . $this->quote->numberFormatter().'.pdf'); + $this->quote->invitations->each(function ($invitation){ + + UnlinkFile::dispatchNow(config('filesystems.default'), $this->quote->client->quote_filepath($invitation) . $this->quote->numberFormatter().'.pdf'); + + }); return $this; } diff --git a/app/Services/Recurring/GetInvoicePdf.php b/app/Services/Recurring/GetInvoicePdf.php index 6c4b6dee22..9a68b5bf56 100644 --- a/app/Services/Recurring/GetInvoicePdf.php +++ b/app/Services/Recurring/GetInvoicePdf.php @@ -37,7 +37,7 @@ class GetInvoicePdf extends AbstractService $invitation = $this->entity->invitations->where('client_contact_id', $this->contact->id)->first(); - $path = $this->entity->client->recurring_invoice_filepath(); + $path = $this->entity->client->recurring_invoice_filepath($invitation); $file_path = $path.$this->entity->hashed_id.'.pdf'; diff --git a/app/Services/Recurring/RecurringService.php b/app/Services/Recurring/RecurringService.php index 65c80791ff..e8a2761b48 100644 --- a/app/Services/Recurring/RecurringService.php +++ b/app/Services/Recurring/RecurringService.php @@ -87,7 +87,13 @@ class RecurringService public function deletePdf() { - UnlinkFile::dispatchNow(config('filesystems.default'), $this->recurring_entity->client->recurring_invoice_filepath() . $this->recurring_entity->numberFormatter().'.pdf'); + + $this->recurring_entity->invitations->each(function ($invitation){ + + UnlinkFile::dispatchNow(config('filesystems.default'), $this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'); + + }); + return $this; } diff --git a/app/Utils/PhantomJS/Phantom.php b/app/Utils/PhantomJS/Phantom.php index 3692099794..6a75c1e49f 100644 --- a/app/Utils/PhantomJS/Phantom.php +++ b/app/Utils/PhantomJS/Phantom.php @@ -62,19 +62,19 @@ class Phantom $entity_obj = $invitation->{$entity}; if ($entity == 'invoice') { - $path = $entity_obj->client->invoice_filepath(); + $path = $entity_obj->client->invoice_filepath($invitation); } if ($entity == 'quote') { - $path = $entity_obj->client->quote_filepath(); + $path = $entity_obj->client->quote_filepath($invitation); } if ($entity == 'credit') { - $path = $entity_obj->client->credit_filepath(); + $path = $entity_obj->client->credit_filepath($invitation); } if ($entity == 'recurring_invoice') { - $path = $entity_obj->client->recurring_invoice_filepath(); + $path = $entity_obj->client->recurring_invoice_filepath($invitation); } $file_path = $path.$entity_obj->numberFormatter().'.pdf'; From 0fb7f5885111e2d782eea164e30d8c8551eaa4a7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Jun 2021 09:58:23 +1000 Subject: [PATCH 03/19] code cleanup --- app/Helpers/Mail/GmailTransportConfig.php | 47 ----------------------- app/Http/Controllers/EmailController.php | 2 +- app/Jobs/Entity/CreateEntityPdf.php | 4 +- app/Providers/MailServiceProvider.php | 2 +- 4 files changed, 5 insertions(+), 50 deletions(-) delete mode 100644 app/Helpers/Mail/GmailTransportConfig.php diff --git a/app/Helpers/Mail/GmailTransportConfig.php b/app/Helpers/Mail/GmailTransportConfig.php deleted file mode 100644 index 68a5a52527..0000000000 --- a/app/Helpers/Mail/GmailTransportConfig.php +++ /dev/null @@ -1,47 +0,0 @@ - 'david@invoiceninja.com', - ]; - - $user = MultiDB::hasUser($query); - // $oauth_user = Socialite::driver('google')->stateless()->userFromToken($user->oauth_user_token); - - // $user->oauth_user_token = $oauth_user->refreshToken; - // $user->save(); - - Config::set('mail.driver', 'gmail'); - Config::set('services.gmail.token', $user->oauth_user_token); - (new MailServiceProvider(app()))->register(); - - Mail::to('david@romulus.com.au') - ->send(new SupportMessageSent('a cool message')); - } -} diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index 2689e3aadd..dd884a9f83 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(); EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data) - ->delay(now()->addSeconds(60)); + ->delay(now()->addSeconds(30)); } diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 4982c786a9..7a6456229c 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -192,7 +192,9 @@ class CreateEntityPdf implements ShouldQueue if ($pdf) { try{ - + + nlog($file_path); + Storage::disk($this->disk)->put($file_path, $pdf); } diff --git a/app/Providers/MailServiceProvider.php b/app/Providers/MailServiceProvider.php index 3ccdc93a46..6f1da83db1 100644 --- a/app/Providers/MailServiceProvider.php +++ b/app/Providers/MailServiceProvider.php @@ -24,7 +24,7 @@ class MailServiceProvider extends MailProvider protected function registerIlluminateMailer() { $this->app->singleton('mail.manager', function($app) { - return new GmailTransportManager($app); + return new GmailTransportManager($app); }); // $this->app->bind('mail.manager', function($app) { From 7709bd32d1e43fe840755d94e97ae1e036bc7959 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Jun 2021 10:18:07 +1000 Subject: [PATCH 04/19] Ensure directories are created prior to PDF generation --- app/Jobs/Company/CompanyExport.php | 6 +++++- app/Jobs/Entity/CreateEntityPdf.php | 3 ++- app/Services/Invoice/GenerateDeliveryNote.php | 3 +++ app/Utils/PhantomJS/Phantom.php | 5 +++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/Jobs/Company/CompanyExport.php b/app/Jobs/Company/CompanyExport.php index aca3306f57..f9447a1357 100644 --- a/app/Jobs/Company/CompanyExport.php +++ b/app/Jobs/Company/CompanyExport.php @@ -480,7 +480,11 @@ class CompanyExport implements ShouldQueue $file_name = date('Y-m-d').'_'.str_replace(' ', '_', $this->company->present()->name() . '_' . $this->company->company_key .'.zip'); - Storage::makeDirectory(public_path('storage/backups/'), 0775); + $path = public_path('storage/backups/'); + + if(!Storage::exists($path)) + Storage::makeDirectory($path, 0775); + $zip_path = public_path('storage/backups/'.$file_name); $zip = new \ZipArchive(); diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 7a6456229c..a4490df40a 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -193,7 +193,8 @@ class CreateEntityPdf implements ShouldQueue try{ - nlog($file_path); + if(!Storage::exists($path)) + Storage::makeDirectory($path, 0775); Storage::disk($this->disk)->put($file_path, $pdf); diff --git a/app/Services/Invoice/GenerateDeliveryNote.php b/app/Services/Invoice/GenerateDeliveryNote.php index e194b6d41d..c416e5e34a 100644 --- a/app/Services/Invoice/GenerateDeliveryNote.php +++ b/app/Services/Invoice/GenerateDeliveryNote.php @@ -106,6 +106,9 @@ class GenerateDeliveryNote info($maker->getCompiledHTML()); } + if(!Storage::exists($this->invoice->client->invoice_filepath($invitation))) + Storage::makeDirectory($this->invoice->client->invoice_filepath($invitation), 0775); + Storage::disk($this->disk)->put($file_path, $pdf); return Storage::disk($this->disk)->path($file_path); diff --git a/app/Utils/PhantomJS/Phantom.php b/app/Utils/PhantomJS/Phantom.php index 6a75c1e49f..90e25917c2 100644 --- a/app/Utils/PhantomJS/Phantom.php +++ b/app/Utils/PhantomJS/Phantom.php @@ -90,6 +90,9 @@ class Phantom $this->checkMime($pdf, $invitation, $entity); + if(!Storage::exists($path)) + Storage::makeDirectory($path, 0775); + $instance = Storage::disk(config('filesystems.default'))->put($file_path, $pdf); return $file_path; @@ -118,8 +121,6 @@ class Phantom $finfo = new \finfo(FILEINFO_MIME); -nlog($pdf); - if($finfo->buffer($pdf) != 'application/pdf; charset=binary') { SystemLogger::dispatch( From 55918d772c4d73e5959ac618175fc6f1ea0d648b Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Jun 2021 13:57:08 +1000 Subject: [PATCH 05/19] Specify disk for storage operations --- app/Jobs/Entity/CreateEntityPdf.php | 6 ++++-- app/Utils/PhantomJS/Phantom.php | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index a4490df40a..6c3d944bf9 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -193,9 +193,11 @@ class CreateEntityPdf implements ShouldQueue try{ - if(!Storage::exists($path)) - Storage::makeDirectory($path, 0775); + if(!Storage::disk(config('filesystems.default'))->exists($path)) + Storage::disk(config('filesystems.default'))->makeDirectory($path, 0775); + nlog($file_path); + Storage::disk($this->disk)->put($file_path, $pdf); } diff --git a/app/Utils/PhantomJS/Phantom.php b/app/Utils/PhantomJS/Phantom.php index 90e25917c2..2b53673042 100644 --- a/app/Utils/PhantomJS/Phantom.php +++ b/app/Utils/PhantomJS/Phantom.php @@ -90,8 +90,8 @@ class Phantom $this->checkMime($pdf, $invitation, $entity); - if(!Storage::exists($path)) - Storage::makeDirectory($path, 0775); + if(!Storage::disk(config('filesystems.default'))->exists($path)) + Storage::disk(config('filesystems.default'))->makeDirectory($path, 0775); $instance = Storage::disk(config('filesystems.default'))->put($file_path, $pdf); From 0a0ea468515778f259bcd6fa389d19c981894794 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Jun 2021 14:09:33 +1000 Subject: [PATCH 06/19] Declare disk for storage --- app/Jobs/Entity/CreateEntityPdf.php | 4 ++-- app/Services/Invoice/GenerateDeliveryNote.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 6c3d944bf9..1d20f5716a 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -193,8 +193,8 @@ class CreateEntityPdf implements ShouldQueue try{ - if(!Storage::disk(config('filesystems.default'))->exists($path)) - Storage::disk(config('filesystems.default'))->makeDirectory($path, 0775); + if(!Storage::disk($this->disk)->exists($path)) + Storage::disk($this->disk)->makeDirectory($path, 0775); nlog($file_path); diff --git a/app/Services/Invoice/GenerateDeliveryNote.php b/app/Services/Invoice/GenerateDeliveryNote.php index c416e5e34a..9f324680f6 100644 --- a/app/Services/Invoice/GenerateDeliveryNote.php +++ b/app/Services/Invoice/GenerateDeliveryNote.php @@ -106,8 +106,8 @@ class GenerateDeliveryNote info($maker->getCompiledHTML()); } - if(!Storage::exists($this->invoice->client->invoice_filepath($invitation))) - Storage::makeDirectory($this->invoice->client->invoice_filepath($invitation), 0775); + if(!Storage::disk($this->disk)->exists($this->invoice->client->invoice_filepath($invitation))) + Storage::disk($this->disk)->makeDirectory($this->invoice->client->invoice_filepath($invitation), 0775); Storage::disk($this->disk)->put($file_path, $pdf); From 59fcbfe52cf91d063e89d4ce0f306d27faffb93f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Jun 2021 14:19:40 +1000 Subject: [PATCH 07/19] Don't delete the PDF prior to sending --- app/Http/Controllers/CreditController.php | 2 +- app/Jobs/Entity/CreateEntityPdf.php | 2 +- app/Jobs/Ninja/SendReminders.php | 2 +- app/Jobs/RecurringInvoice/SendRecurring.php | 2 +- app/Jobs/Util/ReminderJob.php | 2 +- app/Jobs/Util/SendFailedEmails.php | 2 +- app/Services/Invoice/TriggeredActions.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 968298e8a5..9feb62c7e4 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -564,7 +564,7 @@ class CreditController extends BaseController // EmailCredit::dispatch($credit, $credit->company); $credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) { - EmailEntity::dispatch($invitation, $credit->company, 'credit')->delay(now()->addSeconds(60)); + EmailEntity::dispatch($invitation, $credit->company, 'credit'); }); diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 1d20f5716a..cd9682e98b 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -105,7 +105,7 @@ class CreateEntityPdf implements ShouldQueue /* Set customized translations _NOW_ */ $t->replace(Ninja::transformTranslations($this->entity->client->getMergedSettings())); - $this->entity->service()->deletePdf(); + // $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/Jobs/Ninja/SendReminders.php b/app/Jobs/Ninja/SendReminders.php index 45d6db5c92..61dc6bdd03 100644 --- a/app/Jobs/Ninja/SendReminders.php +++ b/app/Jobs/Ninja/SendReminders.php @@ -213,7 +213,7 @@ class SendReminders implements ShouldQueue if ($this->checkSendSetting($invoice, $template) && $invoice->company->account->hasFeature(Account::FEATURE_EMAIL_TEMPLATES_REMINDERS)) { nlog("firing email"); - EmailEntity::dispatchNow($invitation, $invitation->company, $template)->delay(now()->addSeconds(60)); + EmailEntity::dispatchNow($invitation, $invitation->company, $template); } }); diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index 0fc68bbea7..ba25d51e88 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -96,7 +96,7 @@ class SendRecurring implements ShouldQueue if ($invitation->contact && strlen($invitation->contact->email) >=1) { try{ - EmailEntity::dispatch($invitation, $invoice->company)->delay(now()->addSeconds(60)); + EmailEntity::dispatch($invitation, $invoice->company); } catch(\Exception $e) { nlog($e->getMessage()); diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index 8a53bd0a50..cb1068cc0d 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -60,7 +60,7 @@ class ReminderJob implements ShouldQueue $invoice->service()->touchReminder($reminder_template)->save(); $invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) { - EmailEntity::dispatch($invitation, $invitation->company, $reminder_template)->delay(now()->addSeconds(60)); + EmailEntity::dispatch($invitation, $invitation->company, $reminder_template); nlog("Firing reminder email for invoice {$invoice->number}"); }); diff --git a/app/Jobs/Util/SendFailedEmails.php b/app/Jobs/Util/SendFailedEmails.php index d8c9fc2513..33d8f0e0e0 100644 --- a/app/Jobs/Util/SendFailedEmails.php +++ b/app/Jobs/Util/SendFailedEmails.php @@ -64,7 +64,7 @@ class SendFailedEmails implements ShouldQueue if ($invitation->invoice) { if ($invitation->contact->send_email && $invitation->contact->email) { - EmailEntity::dispatch($invitation, $invitation->company, $job_meta_array['reminder_template'])->delay(now()->addSeconds(60)); + EmailEntity::dispatch($invitation, $invitation->company, $job_meta_array['reminder_template']); } } }); diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php index d62bc2cece..74dc9dcbbe 100644 --- a/app/Services/Invoice/TriggeredActions.php +++ b/app/Services/Invoice/TriggeredActions.php @@ -62,7 +62,7 @@ class TriggeredActions extends AbstractService $reminder_template = 'payment'; $this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($reminder_template) { - EmailEntity::dispatch($invitation, $this->invoice->company, $reminder_template)->delay(now()->addSeconds(60)); + EmailEntity::dispatch($invitation, $this->invoice->company, $reminder_template); }); if ($this->invoice->invitations->count() > 0) { From a42223a0be12ec4e6dbbeecd7389fbb56a51d31d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 13 Jun 2021 19:44:33 +1000 Subject: [PATCH 08/19] Clean up filesystem: --- app/Console/Commands/S3Cleanup.php | 74 +++++++++++++++++++++++++++++ app/Jobs/Entity/CreateEntityPdf.php | 1 + 2 files changed, 75 insertions(+) create mode 100644 app/Console/Commands/S3Cleanup.php diff --git a/app/Console/Commands/S3Cleanup.php b/app/Console/Commands/S3Cleanup.php new file mode 100644 index 0000000000..f0609e234c --- /dev/null +++ b/app/Console/Commands/S3Cleanup.php @@ -0,0 +1,74 @@ +pluck('company_key'); + $c2 = Company::on('db-ninja-02')->pluck('company_key'); + + $merged = $c1->merge($c2); + + $c3 = Storage::disk(config('filesystems.default'))->directories(); + + $diff = $merged->diff($c3); + + $this->LogMessage("Disk Cleanup"); + + $this->logMessage("Folders to delete = ". $c1->count()); + + $diff->each(function ($dir){ + + $this->logMessage("Deleting $dir"); + + Storage::deleteDirectory($dir); + + }); + + $this->logMessage("exiting"); + + } + + private function logMessage($str) + { + $str = date('Y-m-d h:i:s').' '.$str; + $this->info($str); + $this->log .= $str."\n"; + } +} diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index cd9682e98b..d86ee6b041 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -105,6 +105,7 @@ 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') { From 2b6f0870b3b29809fafc8703693c06f3c41808b2 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 13 Jun 2021 20:09:52 +1000 Subject: [PATCH 09/19] Tests for clean up S3 orphans --- app/Console/Commands/S3Cleanup.php | 23 ++++++++---------- tests/Unit/S3CleanupTest.php | 39 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 tests/Unit/S3CleanupTest.php diff --git a/app/Console/Commands/S3Cleanup.php b/app/Console/Commands/S3Cleanup.php index f0609e234c..f7409764b3 100644 --- a/app/Console/Commands/S3Cleanup.php +++ b/app/Console/Commands/S3Cleanup.php @@ -43,23 +43,20 @@ class S3Cleanup extends Command $c1 = Company::on('db-ninja-01')->pluck('company_key'); $c2 = Company::on('db-ninja-02')->pluck('company_key'); - $merged = $c1->merge($c2); + $merged = $c1->merge($c2)->toArray(); - $c3 = Storage::disk(config('filesystems.default'))->directories(); - - $diff = $merged->diff($c3); + $directories = Storage::disk(config('filesystems.default'))->directories(); $this->LogMessage("Disk Cleanup"); - $this->logMessage("Folders to delete = ". $c1->count()); - - $diff->each(function ($dir){ - - $this->logMessage("Deleting $dir"); - - Storage::deleteDirectory($dir); - - }); + foreach($directories as $dir) + { + if(!in_array($dir, $merged)) + { + $this->logMessage("Deleting $dir"); + Storage::disk(config('filesystems.default'))->deleteDirectory($dir); + } + } $this->logMessage("exiting"); diff --git a/tests/Unit/S3CleanupTest.php b/tests/Unit/S3CleanupTest.php new file mode 100644 index 0000000000..b4056ff4f5 --- /dev/null +++ b/tests/Unit/S3CleanupTest.php @@ -0,0 +1,39 @@ +merge($c2)->toArray(); + + $this->assertTrue(in_array("1", $merged)); + $this->assertFalse(in_array("10", $merged)); + + } +} From 46ae91f92078fdd2f894a6e57c50062f060bbe50 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 13 Jun 2021 20:47:49 +1000 Subject: [PATCH 10/19] Fixes for regex for subdomain name --- app/Http/Requests/Company/StoreCompanyRequest.php | 2 +- app/Http/Requests/Company/UpdateCompanyRequest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/Company/StoreCompanyRequest.php b/app/Http/Requests/Company/StoreCompanyRequest.php index 12b3c9a26e..3fb397608d 100644 --- a/app/Http/Requests/Company/StoreCompanyRequest.php +++ b/app/Http/Requests/Company/StoreCompanyRequest.php @@ -49,7 +49,7 @@ class StoreCompanyRequest extends Request } else { if(Ninja::isHosted()){ - $rules['subdomain'] = ['nullable', 'alpha_num', new ValidSubdomain($this->all())]; + $rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/', new ValidSubdomain($this->all())]; } else $rules['subdomain'] = 'nullable|alpha_num'; diff --git a/app/Http/Requests/Company/UpdateCompanyRequest.php b/app/Http/Requests/Company/UpdateCompanyRequest.php index 42fb295e7f..01b94b28de 100644 --- a/app/Http/Requests/Company/UpdateCompanyRequest.php +++ b/app/Http/Requests/Company/UpdateCompanyRequest.php @@ -50,7 +50,7 @@ class UpdateCompanyRequest extends Request } else { if(Ninja::isHosted()){ - $rules['subdomain'] = ['nullable', 'alpha_num', new ValidSubdomain($this->all())]; + $rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/', new ValidSubdomain($this->all())]; } else $rules['subdomain'] = 'nullable|alpha_num'; From c67998219e10796d30c8ad75b971cfcb8b276a9e Mon Sep 17 00:00:00 2001 From: = Date: Sun, 13 Jun 2021 22:56:33 +1000 Subject: [PATCH 11/19] invoice_total_raw --- app/Utils/HtmlEngine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 4db72206fd..c1a8e791c9 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -181,6 +181,7 @@ class HtmlEngine $data['$amount_due'] = ['value' => &$data['$total']['value'], 'label' => ctrans('texts.amount_due')]; $data['$quote.total'] = &$data['$total']; $data['$invoice.total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.invoice_total')]; + $data['$invoice_total_raw'] = ['value' => $this->entity_calc->getTotal(), 'label' => ctrans('texts.invoice_total')]; $data['$invoice.amount'] = &$data['$total']; $data['$quote.amount'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.quote_total')]; $data['$credit.total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_total')]; From 1397c9ab1c42260ec27ea2fbd180f36dc3f7dad2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Jun 2021 17:04:15 +1000 Subject: [PATCH 12/19] Fixes logic for hosted login --- app/Http/Controllers/Auth/LoginController.php | 26 +++++++++++++------ tests/Integration/MultiDBUserTest.php | 4 ++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 293a0eb665..97abc500b8 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -222,14 +222,9 @@ class LoginController extends BaseController }); - // $cu->first()->account->companies->each(function ($company) use($cu, $request){ - - // if($company->tokens()->where('is_system', true)->count() == 0) - // { - // CreateCompanyToken::dispatchNow($company, $cu->first()->user, $request->server('HTTP_USER_AGENT')); - // } - - // }); + /*On the hosted platform, only owners can login for free/pro accounts*/ + if(Ninja::isHosted() && !$cu->first()->is_owner && !$user->account->isEnterpriseClient()) + return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403); return $this->timeConstrainedResponse($cu); @@ -318,6 +313,9 @@ class LoginController extends BaseController if($request->has('current_company') && $request->input('current_company') == 'true') $cu->where("company_id", $company_token->company_id); + if(Ninja::isHosted() && !$cu->first()->is_owner && !$cu->first()->user->account->isEnterpriseClient()) + return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403); + return $this->refreshResponse($cu); } @@ -379,6 +377,9 @@ class LoginController extends BaseController } }); + if(Ninja::isHosted() && !$cu->first()->is_owner && !$existing_user->account->isEnterpriseClient()) + return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403); + return $this->timeConstrainedResponse($cu); } @@ -407,6 +408,9 @@ class LoginController extends BaseController } }); + if(Ninja::isHosted() && !$cu->first()->is_owner && !$existing_login_user->account->isEnterpriseClient()) + return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403); + return $this->timeConstrainedResponse($cu); } @@ -439,6 +443,9 @@ class LoginController extends BaseController } }); + if(Ninja::isHosted() && !$cu->first()->is_owner && !$existing_login_user->account->isEnterpriseClient()) + return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403); + return $this->timeConstrainedResponse($cu); } @@ -478,6 +485,9 @@ class LoginController extends BaseController } }); + if(Ninja::isHosted() && !$cu->first()->is_owner && !auth()->user()->account->isEnterpriseClient()) + return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403); + return $this->timeConstrainedResponse($cu); } diff --git a/tests/Integration/MultiDBUserTest.php b/tests/Integration/MultiDBUserTest.php index 311493f1e4..8f3abf239a 100644 --- a/tests/Integration/MultiDBUserTest.php +++ b/tests/Integration/MultiDBUserTest.php @@ -194,6 +194,8 @@ class MultiDBUserTest extends TestCase ], ]; + $response = false; + try { $response = $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), @@ -203,7 +205,7 @@ class MultiDBUserTest extends TestCase } catch (ValidationException $e) { $message = json_decode($e->validator->getMessageBag(), 1); $this->assertNotNull($message); - + nlog($message); } if ($response) { From d2d6a9fe5aaf94bdeecda60cf39f9f6aa74a7e2b Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Jun 2021 17:09:05 +1000 Subject: [PATCH 13/19] Changes to CompanyImport logic - allow multiple users to be imported - however we prevent them from logging in if their plan isn't Enterprise --- app/Jobs/Company/CompanyImport.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Jobs/Company/CompanyImport.php b/app/Jobs/Company/CompanyImport.php index 3c010945c3..977f7d95dc 100644 --- a/app/Jobs/Company/CompanyImport.php +++ b/app/Jobs/Company/CompanyImport.php @@ -219,7 +219,7 @@ class CompanyImport implements ShouldQueue if(count($backup_users) > 1){ // $this->message = 'Only one user can be in the import for a Free Account'; // $this->pre_flight_checks_pass = false; - $this->force_user_coalesce = true; + //$this->force_user_coalesce = true; } nlog("backup users email = " . $backup_users[0]->email); @@ -227,7 +227,7 @@ class CompanyImport implements ShouldQueue if(count($backup_users) == 1 && $this->company_owner->email != $backup_users[0]->email) { // $this->message = 'Account emails do not match. Account owner email must match backup user email'; // $this->pre_flight_checks_pass = false; - $this->force_user_coalesce = true; + // $this->force_user_coalesce = true; } $backup_users_emails = array_column($backup_users, 'email'); @@ -243,7 +243,7 @@ class CompanyImport implements ShouldQueue if($this->account->plan == 'pro'){ // $this->message = 'Pro plan is limited to one user, you have multiple users in the backup file'; // $this->pre_flight_checks_pass = false; - $this->force_user_coalesce = true; + // $this->force_user_coalesce = true; } if($this->account->plan == 'enterprise'){ From 7469ca30eb8b2cfeaa531cda0cc77ef0ddefb1f0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Jun 2021 18:06:34 +1000 Subject: [PATCH 14/19] HostedUsers console command --- app/Console/Commands/HostedUsers.php | 59 ++++++++++++++++++++++++++++ app/Jobs/Account/CreateAccount.php | 11 ++---- 2 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 app/Console/Commands/HostedUsers.php diff --git a/app/Console/Commands/HostedUsers.php b/app/Console/Commands/HostedUsers.php new file mode 100644 index 0000000000..793ff965a0 --- /dev/null +++ b/app/Console/Commands/HostedUsers.php @@ -0,0 +1,59 @@ +all()->each(function ($company){ + + if(Ninja::isHosted()) + \Modules\Admin\Jobs\Account\NinjaUser::dispatchNow([], $company); + + }); + + Company::on('db-ninja-02')->all()->each(function ($company){ + + if(Ninja::isHosted()) + \Modules\Admin\Jobs\Account\NinjaUser::dispatchNow([], $company); + + }); + } + +} diff --git a/app/Jobs/Account/CreateAccount.php b/app/Jobs/Account/CreateAccount.php index 32490cf2e0..6be9106205 100644 --- a/app/Jobs/Account/CreateAccount.php +++ b/app/Jobs/Account/CreateAccount.php @@ -104,7 +104,10 @@ class CreateAccount //todo implement SLACK notifications //$sp035a66->notification(new NewAccountCreated($spaa9f78, $sp035a66))->ninja(); - VersionCheck::dispatchNow(); + if(Ninja::isHosted()) + \Modules\Admin\Jobs\Account\NinjaUser::dispatch([], $sp035a66); + + VersionCheck::dispatch(); LightLogs::create(new AnalyticsAccountCreated()) ->increment() @@ -118,10 +121,6 @@ class CreateAccount if(Ninja::isHosted() && Cache::get('currencies')) { - //&& $data = unserialize(@file_get_contents('http://www.geoplugin.net/php.gp?ip=' . $this->client_ip)) - // $currency_code = strtolower($data['geoplugin_currencyCode']); - // $country_code = strtolower($data['geoplugin_countryCode']); - $currency = Cache::get('currencies')->filter(function ($item) use ($currency_code) { return strtolower($item->code) == $currency_code; })->first(); @@ -146,8 +145,6 @@ class CreateAccount $settings->language_id = (string)$language->id; } - //$timezone = Timezone::where('name', $data['geoplugin_timezone'])->first(); - if($timezone) { $settings->timezone_id = (string)$timezone->id; } From 2e1a6ef6c42456e11d919ca6afb92fd1d86265c7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Jun 2021 18:10:46 +1000 Subject: [PATCH 15/19] HostedUsers console command --- app/Console/Commands/HostedUsers.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Console/Commands/HostedUsers.php b/app/Console/Commands/HostedUsers.php index 793ff965a0..621102382e 100644 --- a/app/Console/Commands/HostedUsers.php +++ b/app/Console/Commands/HostedUsers.php @@ -41,19 +41,21 @@ class HostedUsers extends Command */ public function handle() { - Company::on('db-ninja-01')->all()->each(function ($company){ + + Company::on('db-ninja-01')->each(function ($company){ if(Ninja::isHosted()) \Modules\Admin\Jobs\Account\NinjaUser::dispatchNow([], $company); }); - Company::on('db-ninja-02')->all()->each(function ($company){ + Company::on('db-ninja-02')->each(function ($company){ if(Ninja::isHosted()) \Modules\Admin\Jobs\Account\NinjaUser::dispatchNow([], $company); }); + } } From 9db0758cc1ef8405fd9ff00052c723ab619db4b9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 14 Jun 2021 19:13:48 +1000 Subject: [PATCH 16/19] Update license --- LICENSE | 2 ++ 1 file changed, 2 insertions(+) diff --git a/LICENSE b/LICENSE index e92123e414..8427bcbcea 100644 --- a/LICENSE +++ b/LICENSE @@ -45,3 +45,5 @@ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +For more information regarding the interpretation of this license please see here: https://invoiceninja.github.io/docs/legal/license/ \ No newline at end of file From 887bc3d4a6781f76cb4087c99929c7ef7f18f7b1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Jun 2021 08:06:01 +1000 Subject: [PATCH 17/19] Fixes for reminders --- app/Jobs/Util/ReminderJob.php | 6 +++++- app/Services/Invoice/InvoiceService.php | 3 ++- app/Services/Invoice/UpdateReminder.php | 7 +++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index cb1068cc0d..71300863de 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -53,7 +53,11 @@ class ReminderJob implements ShouldQueue private function processReminders() { - Invoice::whereDate('next_send_date', '<=', now())->with('invitations')->cursor()->each(function ($invoice) { + Invoice::whereDate('next_send_date', '<=', now()) + ->where('is_deleted', 0) + ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) + ->where('balance', '>', 0) + ->with('invitations')->cursor()->each(function ($invoice) { if ($invoice->isPayable()) { $reminder_template = $invoice->calculateTemplate('invoice'); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 8ac66ed6c7..304d83233e 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -392,7 +392,8 @@ class InvoiceService $this->invoice->reminder_last_sent = now()->format('Y-m-d'); break; default: - // code... + $this->invoice->reminder1_sent = now()->format('Y-m-d'); + $this->invoice->reminder_last_sent = now()->format('Y-m-d'); break; } diff --git a/app/Services/Invoice/UpdateReminder.php b/app/Services/Invoice/UpdateReminder.php index 5f2090a4cd..f08d873b9d 100644 --- a/app/Services/Invoice/UpdateReminder.php +++ b/app/Services/Invoice/UpdateReminder.php @@ -126,8 +126,11 @@ class UpdateReminder extends AbstractService $date_collection->push($reminder_date); } - $this->invoice->next_send_date = $date_collection->sort()->first(); - + if($date_collection->count() >=1) + $this->invoice->next_send_date = $date_collection->sort()->first(); + else + $this->invoice->next_send_date = null; + return $this->invoice; } } \ No newline at end of file From d582e6796283e985fea12da8d18a038d602b0fce Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Jun 2021 08:19:23 +1000 Subject: [PATCH 18/19] Fixes for Stripe import customers --- app/PaymentDrivers/Stripe/UpdatePaymentMethods.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Stripe/UpdatePaymentMethods.php b/app/PaymentDrivers/Stripe/UpdatePaymentMethods.php index 8d4e975796..3e83847a97 100644 --- a/app/PaymentDrivers/Stripe/UpdatePaymentMethods.php +++ b/app/PaymentDrivers/Stripe/UpdatePaymentMethods.php @@ -58,7 +58,7 @@ class UpdatePaymentMethods // } - private function updateMethods(Customer $customer, Client $client) + public function updateMethods(Customer $customer, Client $client) { $card_methods = PaymentMethod::all([ 'customer' => $customer->id, @@ -145,7 +145,7 @@ class UpdatePaymentMethods } - private function buildPaymentMethodMeta(PaymentMethod $method, GatewayType $type_id) + private function buildPaymentMethodMeta(PaymentMethod $method, $type_id) { switch ($type_id) { From bb06fe6edde8f33c9f81efe440d202d1d570cd6c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 15 Jun 2021 08:20:52 +1000 Subject: [PATCH 19/19] v5.2.2 --- VERSION.txt | 2 +- config/ninja.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 804440660c..fb467b1573 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.2.1 \ No newline at end of file +5.2.2 \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 2d9866d9a9..dae4a2fdcc 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.2.1', - 'app_tag' => '5.2.1-release', + 'app_version' => '5.2.2', + 'app_tag' => '5.2.2-release', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''),