diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 94c3bf14393a..2307feb938ee 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -55,6 +55,8 @@ class Kernel extends ConsoleKernel $schedule->job(new UpdateExchangeRates)->daily(); + $schedule->job(new RecurringInvoicesCron)->hourly(); + /* Run hosted specific jobs */ if (Ninja::isHosted()) { $schedule->job(new AdjustEmailQuota())->daily(); diff --git a/app/Jobs/Cron/RecurringInvoicesCron.php b/app/Jobs/Cron/RecurringInvoicesCron.php index c6d693c70b74..0eff1fbd0f9a 100644 --- a/app/Jobs/Cron/RecurringInvoicesCron.php +++ b/app/Jobs/Cron/RecurringInvoicesCron.php @@ -37,21 +37,24 @@ class RecurringInvoicesCron public function handle() : void { /* Get all invoices where the send date is less than NOW + 30 minutes() */ + info("Sending recurring invoices {now()}"); if (! config('ninja.db.multi_db_enabled')) { - $recurring_invoices = RecurringInvoice::where('next_send_date', '<=', Carbon::now()->addMinutes(30))->get(); + + $recurring_invoices = RecurringInvoice::where('next_send_date', '<=', Carbon::now()->addMinutes(30))->cursor(); Log::info(Carbon::now()->addMinutes(30).' Sending Recurring Invoices. Count = '.$recurring_invoices->count()); $recurring_invoices->each(function ($recurring_invoice, $key) { SendRecurring::dispatch($recurring_invoice, $recurring_invoice->company->db); }); + } else { //multiDB environment, need to foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); - $recurring_invoices = RecurringInvoice::where('next_send_date', '<=', Carbon::now()->addMinutes(30))->get(); + $recurring_invoices = RecurringInvoice::where('next_send_date', '<=', Carbon::now()->addMinutes(30))->cursor(); Log::info(Carbon::now()->addMinutes(30).' Sending Recurring Invoices. Count = '.$recurring_invoices->count().'On Database # '.$db); diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index 2486ad3a8181..82e645f24ace 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -11,7 +11,10 @@ namespace App\Jobs\RecurringInvoice; +use App\Events\Invoice\InvoiceWasEmailed; use App\Factory\RecurringInvoiceToInvoiceFactory; +use App\Helpers\Email\InvoiceEmail; +use App\Jobs\Invoice\EmailInvoice; use App\Models\Invoice; use App\Models\RecurringInvoice; use App\Utils\Traits\GeneratesCounter; @@ -53,29 +56,40 @@ class SendRecurring implements ShouldQueue // Generate Standard Invoice $invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client); - $invoice->number = $this->getNextRecurringInvoiceNumber($this->recurring_invoice->client); - $invoice->status_id = Invoice::STATUS_SENT; - $invoice->save(); + $invoice = $invoice->service() + ->markSent() + ->applyRecurringNumber() + ->createInvitations() + ->save(); - // Queue: Emails for invoice - // foreach invoice->invitations + $invoice->invitations->each(function ($invitation) use ($invoice) { - // Fire Payment if auto-bill is enabled - if ($this->recurring_invoice->settings->auto_bill) { - //PAYMENT ACTION HERE TODO + $email_builder = (new InvoiceEmail())->build($invitation); - // Clean up recurring invoice object + EmailInvoice::dispatch($email_builder, $invitation, $invoice->company); - $this->recurring_invoice->remaining_cycles = $this->recurring_invoice->remainingCycles(); - } + info("Firing email for invoice {$invoice->number}"); + + }); + + /* Set next date here to prevent a recurring loop forming */ + $this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate()->format('Y-m-d'); + $this->recurring_invoice->remaining_cycles = $this->recurring_invoice->remainingCycles(); $this->recurring_invoice->last_sent_date = date('Y-m-d'); - if ($this->recurring_invoice->remaining_cycles != 0) { - $this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate()->format('Y-m-d'); - } else { + /* Set completed if we don't have any more cycles remaining*/ + if ($this->recurring_invoice->remaining_cycles == 0) $this->recurring_invoice->setCompleted(); - } $this->recurring_invoice->save(); + + if ($invoice->invitations->count() > 0) + event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars())); + + // Fire Payment if auto-bill is enabled + if ($this->recurring_invoice->auto_bill) + $invoice->service()->autoBill()->save(); + } + } diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index 13c0fa5b815e..f03a2e5e95b2 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -56,14 +56,16 @@ class ReminderJob implements ShouldQueue $this->processReminders($db); } } + } private function processReminders($db = null) { - $invoices = Invoice::where('next_send_date', Carbon::today()->format('Y-m-d'))->get(); - $invoices->each(function ($invoice) { + Invoice::where('next_send_date', Carbon::today()->format('Y-m-d'))->with('invitations')->cursor()->each(function ($invoice) { + if ($invoice->isPayable()) { + $invoice->invitations->each(function ($invitation) use ($invoice) { $email_builder = (new InvoiceEmail())->build($invitation); @@ -72,13 +74,18 @@ class ReminderJob implements ShouldQueue info("Firing email for invoice {$invoice->number}"); }); - if ($invoice->invitations->count() > 0) { + if ($invoice->invitations->count() > 0) event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars())); - } + + } else { + $invoice->next_send_date = null; $invoice->save(); + } + }); + } } diff --git a/app/Services/Invoice/ApplyRecurringNumber.php b/app/Services/Invoice/ApplyRecurringNumber.php new file mode 100644 index 000000000000..50a5b14b68cf --- /dev/null +++ b/app/Services/Invoice/ApplyRecurringNumber.php @@ -0,0 +1,62 @@ +client = $client; + + $this->invoice = $invoice; + } + + public function run() + { + if ($this->invoice->number != '') { + return $this->invoice; + } + + switch ($this->client->getSetting('counter_number_applied')) { + case 'when_saved': + $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client);; + break; + case 'when_sent': + if ($this->invoice->status_id == Invoice::STATUS_SENT) { + $this->invoice->number = $this->getNextRecurringInvoiceNumber($this->client);; + } + break; + + default: + // code... + break; + } + + return $this->invoice; + } +} diff --git a/app/Services/Invoice/AutoBillInvoice.php b/app/Services/Invoice/AutoBillInvoice.php index ee76aa4a1973..8ce07c3c8b8c 100644 --- a/app/Services/Invoice/AutoBillInvoice.php +++ b/app/Services/Invoice/AutoBillInvoice.php @@ -74,22 +74,6 @@ class AutoBillInvoice extends AbstractService $payment = $gateway_token->gateway->driver($this->client)->tokenBilling($gateway_token, $payment_hash); - //this is redundant - taken care of much further down. - // if($payment){ - - // if($this->invoice->partial > 0) - // $amount = $this->invoice->partial; - // else - // $amount = $this->invoice->balance; - - // $this->invoice = $this->invoice->service()->addGatewayFee($gateway_token->gateway, $amount)->save(); - - // } - // else - // { - // //TODO autobill failed - // } - return $this->invoice; } diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 97f96efb55a4..b646ffee4386 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -17,6 +17,7 @@ use App\Models\Payment; use App\Services\Client\ClientService; use App\Services\Invoice\ApplyNumber; use App\Services\Invoice\ApplyPayment; +use App\Services\Invoice\ApplyRecurringNumber; use App\Services\Invoice\AutoBillInvoice; use App\Services\Invoice\CreateInvitations; use App\Services\Invoice\GetInvoicePdf; @@ -64,6 +65,18 @@ class InvoiceService return $this; } + + /** + * Applies the recurring invoice number. + * @return $this InvoiceService object + */ + public function applyRecurringNumber() + { + $this->invoice = (new ApplyRecurringNumber($this->invoice->client, $this->invoice))->run(); + + return $this; + } + /** * Apply a payment amount to an invoice. * @param Payment $payment The Payment diff --git a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php index d3ed44854c1f..5f10098b9f5f 100644 --- a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php +++ b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php @@ -44,13 +44,9 @@ class AddIsPublicToDocumentsTable extends Migration }); Schema::table('recurring_invoices', function ($table) { - $table->string('auto_bill'); + $table->boolean('auto_bill')->default(0); }); - // Schema::table('recurring_expenses', function ($table) { - // $table->string('auto_bill'); - // }); - Schema::table('companies', function ($table) { $table->enum('default_auto_bill', ['off', 'always', 'optin', 'optout'])->default('off'); });