Working on recurring

This commit is contained in:
David Bomba 2020-09-08 20:34:14 +10:00
parent c389ff49f2
commit f5eecf0eb6
8 changed files with 123 additions and 42 deletions

View File

@ -55,6 +55,8 @@ class Kernel extends ConsoleKernel
$schedule->job(new UpdateExchangeRates)->daily(); $schedule->job(new UpdateExchangeRates)->daily();
$schedule->job(new RecurringInvoicesCron)->hourly();
/* Run hosted specific jobs */ /* Run hosted specific jobs */
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
$schedule->job(new AdjustEmailQuota())->daily(); $schedule->job(new AdjustEmailQuota())->daily();

View File

@ -37,21 +37,24 @@ class RecurringInvoicesCron
public function handle() : void public function handle() : void
{ {
/* Get all invoices where the send date is less than NOW + 30 minutes() */ /* 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')) { 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()); Log::info(Carbon::now()->addMinutes(30).' Sending Recurring Invoices. Count = '.$recurring_invoices->count());
$recurring_invoices->each(function ($recurring_invoice, $key) { $recurring_invoices->each(function ($recurring_invoice, $key) {
SendRecurring::dispatch($recurring_invoice, $recurring_invoice->company->db); SendRecurring::dispatch($recurring_invoice, $recurring_invoice->company->db);
}); });
} else { } else {
//multiDB environment, need to //multiDB environment, need to
foreach (MultiDB::$dbs as $db) { foreach (MultiDB::$dbs as $db) {
MultiDB::setDB($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); Log::info(Carbon::now()->addMinutes(30).' Sending Recurring Invoices. Count = '.$recurring_invoices->count().'On Database # '.$db);

View File

@ -11,7 +11,10 @@
namespace App\Jobs\RecurringInvoice; namespace App\Jobs\RecurringInvoice;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Factory\RecurringInvoiceToInvoiceFactory; use App\Factory\RecurringInvoiceToInvoiceFactory;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Invoice\EmailInvoice;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
@ -53,29 +56,40 @@ class SendRecurring implements ShouldQueue
// Generate Standard Invoice // Generate Standard Invoice
$invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client); $invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client);
$invoice->number = $this->getNextRecurringInvoiceNumber($this->recurring_invoice->client); $invoice = $invoice->service()
$invoice->status_id = Invoice::STATUS_SENT; ->markSent()
$invoice->save(); ->applyRecurringNumber()
->createInvitations()
->save();
// Queue: Emails for invoice $invoice->invitations->each(function ($invitation) use ($invoice) {
// foreach invoice->invitations
// Fire Payment if auto-bill is enabled $email_builder = (new InvoiceEmail())->build($invitation);
if ($this->recurring_invoice->settings->auto_bill) {
//PAYMENT ACTION HERE TODO
// Clean up recurring invoice object EmailInvoice::dispatch($email_builder, $invitation, $invoice->company);
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->remaining_cycles = $this->recurring_invoice->remainingCycles();
}
$this->recurring_invoice->last_sent_date = date('Y-m-d'); $this->recurring_invoice->last_sent_date = date('Y-m-d');
if ($this->recurring_invoice->remaining_cycles != 0) { /* Set completed if we don't have any more cycles remaining*/
$this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate()->format('Y-m-d'); if ($this->recurring_invoice->remaining_cycles == 0)
} else {
$this->recurring_invoice->setCompleted(); $this->recurring_invoice->setCompleted();
}
$this->recurring_invoice->save(); $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();
} }
} }

View File

@ -56,14 +56,16 @@ class ReminderJob implements ShouldQueue
$this->processReminders($db); $this->processReminders($db);
} }
} }
} }
private function processReminders($db = null) 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()) { if ($invoice->isPayable()) {
$invoice->invitations->each(function ($invitation) use ($invoice) { $invoice->invitations->each(function ($invitation) use ($invoice) {
$email_builder = (new InvoiceEmail())->build($invitation); $email_builder = (new InvoiceEmail())->build($invitation);
@ -72,13 +74,18 @@ class ReminderJob implements ShouldQueue
info("Firing email for invoice {$invoice->number}"); 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())); event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars()));
}
} else { } else {
$invoice->next_send_date = null; $invoice->next_send_date = null;
$invoice->save(); $invoice->save();
} }
}); });
} }
} }

View File

@ -0,0 +1,62 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Payment;
use App\Services\AbstractService;
use App\Services\Client\ClientService;
use App\Services\Payment\PaymentService;
use App\Utils\Traits\GeneratesCounter;
class ApplyRecurringNumber extends AbstractService
{
use GeneratesCounter;
private $client;
private $invoice;
public function __construct(Client $client, Invoice $invoice)
{
$this->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;
}
}

View File

@ -74,22 +74,6 @@ class AutoBillInvoice extends AbstractService
$payment = $gateway_token->gateway->driver($this->client)->tokenBilling($gateway_token, $payment_hash); $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; return $this->invoice;
} }

View File

@ -17,6 +17,7 @@ use App\Models\Payment;
use App\Services\Client\ClientService; use App\Services\Client\ClientService;
use App\Services\Invoice\ApplyNumber; use App\Services\Invoice\ApplyNumber;
use App\Services\Invoice\ApplyPayment; use App\Services\Invoice\ApplyPayment;
use App\Services\Invoice\ApplyRecurringNumber;
use App\Services\Invoice\AutoBillInvoice; use App\Services\Invoice\AutoBillInvoice;
use App\Services\Invoice\CreateInvitations; use App\Services\Invoice\CreateInvitations;
use App\Services\Invoice\GetInvoicePdf; use App\Services\Invoice\GetInvoicePdf;
@ -64,6 +65,18 @@ class InvoiceService
return $this; 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. * Apply a payment amount to an invoice.
* @param Payment $payment The Payment * @param Payment $payment The Payment

View File

@ -44,13 +44,9 @@ class AddIsPublicToDocumentsTable extends Migration
}); });
Schema::table('recurring_invoices', function ($table) { 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) { Schema::table('companies', function ($table) {
$table->enum('default_auto_bill', ['off', 'always', 'optin', 'optout'])->default('off'); $table->enum('default_auto_bill', ['off', 'always', 'optin', 'optout'])->default('off');
}); });