Working on recurring expenses

This commit is contained in:
Hillel Coren 2017-06-26 12:45:42 +03:00
parent b596845e1a
commit 1baaa76a00
7 changed files with 195 additions and 122 deletions

View File

@ -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();
*/
}
}
/**

View File

@ -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);
}
}

View File

@ -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');

View File

@ -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
*/

View File

@ -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

View 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;
}
*/
}

View File

@ -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');