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 648bb043f..9cc414790 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 62b3e938d..60b64ec24 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 6febb5876..f86191d99 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 54049fa00..a26e41d36 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 047257859..0fec89cc2 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 60b64ec24..4982c786a 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 07a0544b6..fc66984ff 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 07d5b60d3..fae73019d 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 09fe9b9c3..59e1a4c0e 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 cc32c7e26..010e04795 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 901a0c38d..978cff6cd 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 18d3d3636..9181c1f26 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 732a70123..e163e7906 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 242dabd24..3cd4028c6 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 2db1c1316..ffabc6b26 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 f86191d99..5715f4823 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 3fa1f4918..1e55b6075 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 c7d3118dc..dfe32b9e9 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 901d0bc54..c5159cfa2 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 b91436d2e..fddcb6624 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 a07e572eb..48073b577 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 9114ec5fd..11acb7dfc 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 4c8d681a7..e194b6d41 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 8d42aabfb..535d70ddb 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 a26e41d36..8ac66ed6c 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 7990c81a9..a28a09a6b 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 b76846208..76b007896 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 6c4b6dee2..9a68b5bf5 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 65c80791f..e8a2761b4 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 369209979..6a75c1e49 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 68a5a5252..000000000 --- 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 2689e3aad..dd884a9f8 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 4982c786a..7a6456229 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 3ccdc93a4..6f1da83db 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 aca3306f5..f9447a135 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 7a6456229..a4490df40 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 e194b6d41..c416e5e34 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 6a75c1e49..90e25917c 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 a4490df40..6c3d944bf 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 90e25917c..2b5367304 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 6c3d944bf..1d20f5716 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 c416e5e34..9f324680f 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 968298e8a..9feb62c7e 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 1d20f5716..cd9682e98 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 45d6db5c9..61dc6bdd0 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 0fc68bbea..ba25d51e8 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 8a53bd0a5..cb1068cc0 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 d8c9fc251..33d8f0e0e 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 d62bc2cec..74dc9dcbb 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 000000000..f0609e234 --- /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 cd9682e98..d86ee6b04 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 f0609e234..f7409764b 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 000000000..b4056ff4f --- /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 12b3c9a26..3fb397608 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 42fb295e7..01b94b28d 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 4db72206f..c1a8e791c 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 293a0eb66..97abc500b 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 311493f1e..8f3abf239 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 3c010945c..977f7d95d 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 000000000..793ff965a --- /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 32490cf2e..6be910620 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 793ff965a..621102382 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 e92123e41..8427bcbce 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 cb1068cc0..71300863d 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 8ac66ed6c..304d83233 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 5f2090a4c..f08d873b9 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 8d4e97579..3e83847a9 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 804440660..fb467b157 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 2d9866d9a..dae4a2fdc 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', ''),