mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-07 17:04:45 -04:00
Working on recurring expenses
This commit is contained in:
parent
b596845e1a
commit
1baaa76a00
@ -61,13 +61,21 @@ class SendRecurringInvoices extends Command
|
||||
public function fire()
|
||||
{
|
||||
$this->info(date('Y-m-d H:i:s') . ' Running SendRecurringInvoices...');
|
||||
$today = new DateTime();
|
||||
|
||||
if ($database = $this->option('database')) {
|
||||
config(['database.default' => $database]);
|
||||
}
|
||||
|
||||
// check for counter resets
|
||||
$this->resetCounters();
|
||||
$this->createInvoices();
|
||||
$this->billInvoices();
|
||||
$this->createExpenses();
|
||||
|
||||
$this->info(date('Y-m-d H:i:s') . ' Done');
|
||||
}
|
||||
|
||||
private function resetCounters()
|
||||
{
|
||||
$accounts = Account::where('reset_counter_frequency_id', '>', 0)
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
@ -75,6 +83,11 @@ class SendRecurringInvoices extends Command
|
||||
foreach ($accounts as $account) {
|
||||
$account->checkCounterReset();
|
||||
}
|
||||
}
|
||||
|
||||
private function createInvoices()
|
||||
{
|
||||
$today = new DateTime();
|
||||
|
||||
$invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user')
|
||||
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND is_public IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today])
|
||||
@ -102,6 +115,11 @@ class SendRecurringInvoices extends Command
|
||||
}
|
||||
Auth::logout();
|
||||
}
|
||||
}
|
||||
|
||||
private function billInvoices()
|
||||
{
|
||||
$today = new DateTime();
|
||||
|
||||
$delayedAutoBillInvoices = Invoice::with('account.timezone', 'recurring_invoice', 'invoice_items', 'client', 'user')
|
||||
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS FALSE AND is_public IS TRUE
|
||||
@ -124,8 +142,42 @@ class SendRecurringInvoices extends Command
|
||||
Auth::logout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->info(date('Y-m-d H:i:s') . ' Done');
|
||||
private function createExpenses()
|
||||
{
|
||||
$today = new DateTime();
|
||||
|
||||
$expenses = Expense::with('client')
|
||||
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today])
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
$this->info(count($expenses).' recurring expenses(s) found');
|
||||
|
||||
foreach ($expenses as $expense) {
|
||||
$shouldSendToday = $expense->shouldSendToday();
|
||||
|
||||
if (! $shouldSendToday) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->info('Processing Expense: '. $expense->id);
|
||||
|
||||
$this->recurringExpenseRepo->createRecurringExpense($expense);
|
||||
|
||||
/*
|
||||
$account = $expense->account;
|
||||
//$account->loadLocalizationSettings($recurInvoice->client);
|
||||
//Auth::loginUsingId($recurInvoice->user_id);
|
||||
$invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice);
|
||||
|
||||
if ($invoice && ! $invoice->isPaid()) {
|
||||
$this->info('Sending Invoice');
|
||||
$this->mailer->sendInvoice($invoice);
|
||||
}
|
||||
Auth::logout();
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,6 +144,10 @@ class RecurringExpenseController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.updated_recurring_expense'));
|
||||
|
||||
if (in_array(Input::get('action'), ['archive', 'delete', 'restore'])) {
|
||||
return self::bulk();
|
||||
}
|
||||
|
||||
return redirect()->to($recurringExpense->getRoute());
|
||||
}
|
||||
|
||||
@ -159,6 +163,6 @@ class RecurringExpenseController extends BaseController
|
||||
Session::flash('message', $message);
|
||||
}
|
||||
|
||||
return redirect()->to('/recurring_expenses');
|
||||
return $this->returnBulk($this->entityType, $action, $ids);
|
||||
}
|
||||
}
|
||||
|
@ -185,6 +185,7 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () {
|
||||
Route::post('recurring_expenses', 'RecurringExpenseController@store');
|
||||
Route::put('recurring_expenses/{recurring_expenses}', 'RecurringExpenseController@update');
|
||||
Route::get('recurring_expenses/{recurring_expenses}/edit', 'RecurringExpenseController@edit');
|
||||
Route::get('recurring_expenses/{recurring_expenses}', 'RecurringExpenseController@edit');
|
||||
Route::post('recurring_expenses/bulk', 'RecurringExpenseController@bulk');
|
||||
|
||||
Route::get('documents/{documents}/{filename?}', 'DocumentController@get');
|
||||
|
@ -11,11 +11,11 @@ use App\Events\QuoteInvitationWasEmailed;
|
||||
use App\Libraries\CurlUtils;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Traits\ChargesFees;
|
||||
use App\Models\Traits\HasRecurrence;
|
||||
use DateTime;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Laracasts\Presenter\PresentableTrait;
|
||||
use Utils;
|
||||
use Carbon;
|
||||
|
||||
/**
|
||||
* Class Invoice.
|
||||
@ -25,6 +25,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
||||
use PresentableTrait;
|
||||
use OwnedByClientTrait;
|
||||
use ChargesFees;
|
||||
use HasRecurrence;
|
||||
use SoftDeletes {
|
||||
SoftDeletes::trashed as parentTrashed;
|
||||
}
|
||||
@ -1117,122 +1118,6 @@ class Invoice extends EntityModel implements BalanceAffecting
|
||||
return implode('<br/>', $dates);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getRecurrenceRule()
|
||||
{
|
||||
$rule = '';
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
case FREQUENCY_WEEKLY:
|
||||
$rule = 'FREQ=WEEKLY;';
|
||||
break;
|
||||
case FREQUENCY_TWO_WEEKS:
|
||||
$rule = 'FREQ=WEEKLY;INTERVAL=2;';
|
||||
break;
|
||||
case FREQUENCY_FOUR_WEEKS:
|
||||
$rule = 'FREQ=WEEKLY;INTERVAL=4;';
|
||||
break;
|
||||
case FREQUENCY_MONTHLY:
|
||||
$rule = 'FREQ=MONTHLY;';
|
||||
break;
|
||||
case FREQUENCY_TWO_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=2;';
|
||||
break;
|
||||
case FREQUENCY_THREE_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=3;';
|
||||
break;
|
||||
case FREQUENCY_SIX_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=6;';
|
||||
break;
|
||||
case FREQUENCY_ANNUALLY:
|
||||
$rule = 'FREQ=YEARLY;';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->end_date) {
|
||||
$rule .= 'UNTIL=' . $this->getOriginal('end_date');
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
/*
|
||||
public function shouldSendToday()
|
||||
{
|
||||
if (!$nextSendDate = $this->getNextSendDate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->account->getDateTime() >= $nextSendDate;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldSendToday()
|
||||
{
|
||||
if (! $this->user->confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$account = $this->account;
|
||||
$timezone = $account->getTimezone();
|
||||
|
||||
if (! $this->start_date || Carbon::parse($this->start_date, $timezone)->isFuture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->end_date && Carbon::parse($this->end_date, $timezone)->isPast()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->last_sent_date) {
|
||||
return true;
|
||||
} else {
|
||||
$date1 = new DateTime($this->last_sent_date);
|
||||
$date2 = new DateTime();
|
||||
$diff = $date2->diff($date1);
|
||||
$daysSinceLastSent = $diff->format('%a');
|
||||
$monthsSinceLastSent = ($diff->format('%y') * 12) + $diff->format('%m');
|
||||
|
||||
// check we don't send a few hours early due to timezone difference
|
||||
if (Carbon::now()->format('Y-m-d') != Carbon::now($timezone)->format('Y-m-d')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check we never send twice on one day
|
||||
if ($daysSinceLastSent == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
case FREQUENCY_WEEKLY:
|
||||
return $daysSinceLastSent >= 7;
|
||||
case FREQUENCY_TWO_WEEKS:
|
||||
return $daysSinceLastSent >= 14;
|
||||
case FREQUENCY_FOUR_WEEKS:
|
||||
return $daysSinceLastSent >= 28;
|
||||
case FREQUENCY_MONTHLY:
|
||||
return $monthsSinceLastSent >= 1;
|
||||
case FREQUENCY_TWO_MONTHS:
|
||||
return $monthsSinceLastSent >= 2;
|
||||
case FREQUENCY_THREE_MONTHS:
|
||||
return $monthsSinceLastSent >= 3;
|
||||
case FREQUENCY_SIX_MONTHS:
|
||||
return $monthsSinceLastSent >= 6;
|
||||
case FREQUENCY_ANNUALLY:
|
||||
return $monthsSinceLastSent >= 12;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
//use App\Events\ExpenseWasCreated;
|
||||
//use App\Events\ExpenseWasUpdated;
|
||||
use App\Models\Traits\HasRecurrence;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Laracasts\Presenter\PresentableTrait;
|
||||
use Utils;
|
||||
@ -16,6 +17,7 @@ class RecurringExpense extends EntityModel
|
||||
// Expenses
|
||||
use SoftDeletes;
|
||||
use PresentableTrait;
|
||||
use HasRecurrence;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
|
129
app/Models/Traits/HasRecurrence.php
Normal file
129
app/Models/Traits/HasRecurrence.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Traits;
|
||||
|
||||
use Carbon;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* Class HasRecurrence
|
||||
*/
|
||||
trait HasRecurrence
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldSendToday()
|
||||
{
|
||||
if (! $this->user->confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$account = $this->account;
|
||||
$timezone = $account->getTimezone();
|
||||
|
||||
if (! $this->start_date || Carbon::parse($this->start_date, $timezone)->isFuture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->end_date && Carbon::parse($this->end_date, $timezone)->isPast()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->last_sent_date) {
|
||||
return true;
|
||||
} else {
|
||||
$date1 = new DateTime($this->last_sent_date);
|
||||
$date2 = new DateTime();
|
||||
$diff = $date2->diff($date1);
|
||||
$daysSinceLastSent = $diff->format('%a');
|
||||
$monthsSinceLastSent = ($diff->format('%y') * 12) + $diff->format('%m');
|
||||
|
||||
// check we don't send a few hours early due to timezone difference
|
||||
if (Carbon::now()->format('Y-m-d') != Carbon::now($timezone)->format('Y-m-d')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check we never send twice on one day
|
||||
if ($daysSinceLastSent == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
case FREQUENCY_WEEKLY:
|
||||
return $daysSinceLastSent >= 7;
|
||||
case FREQUENCY_TWO_WEEKS:
|
||||
return $daysSinceLastSent >= 14;
|
||||
case FREQUENCY_FOUR_WEEKS:
|
||||
return $daysSinceLastSent >= 28;
|
||||
case FREQUENCY_MONTHLY:
|
||||
return $monthsSinceLastSent >= 1;
|
||||
case FREQUENCY_TWO_MONTHS:
|
||||
return $monthsSinceLastSent >= 2;
|
||||
case FREQUENCY_THREE_MONTHS:
|
||||
return $monthsSinceLastSent >= 3;
|
||||
case FREQUENCY_SIX_MONTHS:
|
||||
return $monthsSinceLastSent >= 6;
|
||||
case FREQUENCY_ANNUALLY:
|
||||
return $monthsSinceLastSent >= 12;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getRecurrenceRule()
|
||||
{
|
||||
$rule = '';
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
case FREQUENCY_WEEKLY:
|
||||
$rule = 'FREQ=WEEKLY;';
|
||||
break;
|
||||
case FREQUENCY_TWO_WEEKS:
|
||||
$rule = 'FREQ=WEEKLY;INTERVAL=2;';
|
||||
break;
|
||||
case FREQUENCY_FOUR_WEEKS:
|
||||
$rule = 'FREQ=WEEKLY;INTERVAL=4;';
|
||||
break;
|
||||
case FREQUENCY_MONTHLY:
|
||||
$rule = 'FREQ=MONTHLY;';
|
||||
break;
|
||||
case FREQUENCY_TWO_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=2;';
|
||||
break;
|
||||
case FREQUENCY_THREE_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=3;';
|
||||
break;
|
||||
case FREQUENCY_SIX_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=6;';
|
||||
break;
|
||||
case FREQUENCY_ANNUALLY:
|
||||
$rule = 'FREQ=YEARLY;';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->end_date) {
|
||||
$rule .= 'UNTIL=' . $this->getOriginal('end_date');
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
/*
|
||||
public function shouldSendToday()
|
||||
{
|
||||
if (!$nextSendDate = $this->getNextSendDate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->account->getDateTime() >= $nextSendDate;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
@ -50,7 +50,7 @@ class UpdateDarkMode extends Migration
|
||||
$table->unsignedInteger('frequency_id');
|
||||
$table->date('start_date')->nullable();
|
||||
$table->date('end_date')->nullable();
|
||||
$table->timestamp('last_created_date')->nullable();
|
||||
$table->timestamp('last_sent_date')->nullable();
|
||||
|
||||
// Relations
|
||||
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||
|
Loading…
x
Reference in New Issue
Block a user