diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index e7bd0547bd..77e6b4c391 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -14,6 +14,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Support\Collection; use Input; +use Navigation; use Redirect; use Session; use Steam; @@ -259,6 +260,24 @@ class PiggyBankController extends Controller public function show(PiggyBank $piggyBank) { + /* + * Some reminder debug stuff. + */ + + + // if($piggyBank->remind_me === true) { + // // need to determine sensible moment for a reminder + // // to occur. + // // loop back to today? + // // if no target date, just make reminders out from start date? + // + // $start = $piggyBank->targetdate; + // if(is_null($start)) { + // + // } + // } + + $events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get(); /* @@ -279,17 +298,23 @@ class PiggyBankController extends Controller $piggyBankData = [ 'repeats' => false, 'name' => $request->get('name'), - 'startdate' => null, + 'startdate' => new Carbon, 'account_id' => intval($request->get('account_id')), 'targetamount' => floatval($request->get('targetamount')), 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, 'reminder' => $request->get('reminder'), + 'remind_me' => $request->get('remind_me'), ]; $piggyBank = $repository->store($piggyBankData); Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".'); + if (intval(Input::get('create_another')) === 1) { + return Redirect::route('piggy-banks.create')->withInput(); + } + + return Redirect::route('piggy-banks.index'); } @@ -305,6 +330,7 @@ class PiggyBankController extends Controller $piggyBankData = [ 'repeats' => false, 'name' => $request->get('name'), + 'startdate' => is_null($piggyBank->startdate) ? $piggyBank->created_at : $piggyBank->startdate, 'account_id' => intval($request->get('account_id')), 'targetamount' => floatval($request->get('targetamount')), 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, @@ -315,6 +341,11 @@ class PiggyBankController extends Controller Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".'); + if (intval(Input::get('return_to_edit')) === 1) { + return Redirect::route('piggy-banks.edit', $piggyBank->id); + } + + return Redirect::route('piggy-banks.index'); diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 49bd53d8b0..e492fe899e 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -263,7 +263,7 @@ class TransactionController extends Controller Session::flash('success', 'New transaction "' . $journal->description . '" stored!'); if (intval(Input::get('create_another')) === 1) { - return Redirect::route('transactions.create', $request->input('what')); + return Redirect::route('transactions.create', $request->input('what'))->withInput(); } return Redirect::route('transactions.index', $request->input('what')); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 67ce5757e4..970e795492 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -36,6 +36,7 @@ class Kernel extends HttpKernel 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', 'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated', 'range' => 'FireflyIII\Http\Middleware\Range', + 'reminders' => 'FireflyIII\Http\Middleware\Reminders', ]; } diff --git a/app/Http/Middleware/Reminders.php b/app/Http/Middleware/Reminders.php new file mode 100644 index 0000000000..5e611ebbe6 --- /dev/null +++ b/app/Http/Middleware/Reminders.php @@ -0,0 +1,119 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * + * @return mixed + */ + public function handle($request, Closure $next) + { + if ($this->auth->check()) { + // do reminders stuff. + $piggyBanks = $this->auth->user()->piggyBanks()->where('remind_me', 1)->get(); + $today = new Carbon; + /** @var \FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface $repository */ + $repository = App::make('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); + + /** @var PiggyBank $piggyBank */ + foreach ($piggyBanks as $piggyBank) { + if (!is_null($piggyBank->targetdate)) { + // count back until now. + $start = $piggyBank->targetdate; + $end = $piggyBank->startdate; + + while ($start >= $end) { + $currentEnd = clone $start; + $start = Navigation::subtractPeriod($start, $piggyBank->reminder, 1); + $currentStart = clone $start; + // for today? + if ($today < $currentEnd && $today > $currentStart) { + // find a reminder first? + $reminders = $this->auth->user()->reminders() + ->where('remindersable_id', $piggyBank->id) + ->onDates($currentStart, $currentEnd) + ->count(); + if ($reminders == 0) { + // create a reminder here! + $repository->createReminder($piggyBank, $currentStart, $currentEnd); + } + // stop looping, we're done. + break; + } + + } + } else { + $start = clone $piggyBank->startdate; + while ($start < $today) { + $currentStart = clone $start; + $start = Navigation::addPeriod($start, $piggyBank->reminder, 0); + $currentEnd = clone $start; + + + // for today? + if ($today < $currentEnd && $today > $currentStart) { + $reminders = $this->auth->user()->reminders() + ->where('remindersable_id', $piggyBank->id) + ->onDates($currentStart, $currentEnd) + ->count(); + + if ($reminders == 0) { + // create a reminder here! + $repository->createReminder($piggyBank, $currentStart, $currentEnd); + + } + } + + + } + } + } + + } + + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Requests/PiggyBankFormRequest.php b/app/Http/Requests/PiggyBankFormRequest.php index 74fc66efdb..6917c117d9 100644 --- a/app/Http/Requests/PiggyBankFormRequest.php +++ b/app/Http/Requests/PiggyBankFormRequest.php @@ -51,7 +51,7 @@ class PiggyBankFormRequest extends Request 'rep_times' => 'integer|min:0|max:99', 'reminder' => 'in:day,week,quarter,month,year', 'reminder_skip' => 'integer|min:0|max:99', - 'remind_me' => 'boolean', + 'remind_me' => 'boolean|piggyBankReminder', 'order' => 'integer|min:1', ]; diff --git a/app/Http/routes.php b/app/Http/routes.php index f5bf4953be..66cbcde5eb 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -145,7 +145,7 @@ Route::controllers( * Home Controller */ Route::group( - ['middleware' => ['auth', 'range']], function () { + ['middleware' => ['auth', 'range','reminders']], function () { Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']); Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']); Route::post('/daterange',['uses' => 'HomeController@dateRange','as' => 'daterange']); diff --git a/app/Models/PiggyBank.php b/app/Models/PiggyBank.php index 305a8eb076..38f5fa5690 100644 --- a/app/Models/PiggyBank.php +++ b/app/Models/PiggyBank.php @@ -14,7 +14,7 @@ class PiggyBank extends Model { use SoftDeletes; - protected $fillable = ['repeats', 'name', 'account_id','rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder',]; + protected $fillable = ['repeats', 'name', 'account_id','rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder','remind_me']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo @@ -24,6 +24,15 @@ class PiggyBank extends Model return $this->belongsTo('FireflyIII\Models\Account'); } + /** + * @param $value + * + * @return int + */ + public function getRemindMeAttribute($value) { + return intval($value) == 1; + } + /** * Grabs the PiggyBankRepetition that's currently relevant / active * diff --git a/app/Models/Reminder.php b/app/Models/Reminder.php index 98e75a0a4c..a09eeb73ff 100644 --- a/app/Models/Reminder.php +++ b/app/Models/Reminder.php @@ -1,5 +1,7 @@ morphTo(); } + /** + * @param EloquentBuilder $query + * @param Carbon $date + * + * @return mixed + */ + public function scopeOnDates(EloquentBuilder $query, Carbon $start, Carbon $end) + { + return $query->where('reminders.startdate', '=', $start->format('Y-m-d 00:00:00'))->where('reminders.enddate', '=', $end->format('Y-m-d 00:00:00')); + } + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index a7eaf8f265..aea1304941 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -2,8 +2,11 @@ namespace FireflyIII\Repositories\PiggyBank; +use Auth; +use Carbon\Carbon; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBankRepetition; +use FireflyIII\Models\Reminder; use Illuminate\Support\Collection; use Navigation; @@ -15,49 +18,6 @@ use Navigation; class PiggyBankRepository implements PiggyBankRepositoryInterface { - /** - * @param array $data - * - * @return PiggyBank - */ - public function store(array $data) - { - - $piggyBank = PiggyBank::create($data); - - return $piggyBank; - } - - /** - * @param PiggyBank $account - * @param array $data - * - * @return PiggyBank - */ - public function update(PiggyBank $piggyBank, array $data) - { - /** - 'rep_length' => $request->get('rep_length'), - 'rep_every' => intval($request->get('rep_every')), - 'rep_times' => intval($request->get('rep_times')), - 'remind_me' => intval($request->get('remind_me')) == 1 ? true : false , - 'reminder' => $request->get('reminder'), - */ - - $piggyBank->name = $data['name']; - $piggyBank->account_id = intval($data['account_id']); - $piggyBank->targetamount = floatval($data['targetamount']); - $piggyBank->targetdate = $data['targetdate']; - $piggyBank->reminder = $data['reminder']; - $piggyBank->rep_length = isset($data['rep_length']) ? $data['rep_length'] : null; - $piggyBank->rep_every =isset($data['rep_every']) ? $data['rep_every'] : null; - $piggyBank->rep_times = isset($data['rep_times']) ? $data['rep_times'] : null; - $piggyBank->remind_me = isset($data['remind_me']) ? $data['remind_me'] : null; - - $piggyBank->save(); - return $piggyBank; - } - /** * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. * @@ -126,4 +86,84 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return $part; } + + /** + * @param PiggyBank $piggyBank + * @param Carbon $currentStart + * @param Carbon $currentEnd + * + * @return Reminder + */ + public function createReminder(PiggyBank $piggyBank, Carbon $currentStart, Carbon $currentEnd) + { + $reminder = Auth::user()->reminders() + ->where('remindersable_id', $piggyBank->id) + ->onDates($currentStart, $currentEnd) + ->first(); + if (is_null($reminder)) { + // create one: + $reminder = Reminder::create( + [ + 'user_id' => Auth::user()->id, + 'startdate' => $currentStart->format('Y-m-d'), + 'enddate' => $currentEnd->format('Y-m-d'), + 'active' => '1', + 'notnow' => '0', + 'remindersable_id' => $piggyBank->id, + 'remindersable_type' => 'PiggyBank', + ] + ); + return $reminder; + + } else { + return $reminder; + } + + + } + + /** + * @param array $data + * + * @return PiggyBank + */ + public function store(array $data) + { + $data['remind_me'] = isset($data['remind_me']) && $data['remind_me'] == '1' ? true : false; + $piggyBank = PiggyBank::create($data); + + return $piggyBank; + } + + /** + * @param PiggyBank $account + * @param array $data + * + * @return PiggyBank + */ + public function update(PiggyBank $piggyBank, array $data) + { + /** + * 'rep_length' => $request->get('rep_length'), + * 'rep_every' => intval($request->get('rep_every')), + * 'rep_times' => intval($request->get('rep_times')), + * 'remind_me' => intval($request->get('remind_me')) == 1 ? true : false , + * 'reminder' => $request->get('reminder'), + */ + + $piggyBank->name = $data['name']; + $piggyBank->account_id = intval($data['account_id']); + $piggyBank->targetamount = floatval($data['targetamount']); + $piggyBank->targetdate = $data['targetdate']; + $piggyBank->reminder = $data['reminder']; + $piggyBank->startdate = $data['startdate']; + $piggyBank->rep_length = isset($data['rep_length']) ? $data['rep_length'] : null; + $piggyBank->rep_every = isset($data['rep_every']) ? $data['rep_every'] : null; + $piggyBank->rep_times = isset($data['rep_times']) ? $data['rep_times'] : null; + $piggyBank->remind_me = isset($data['remind_me']) && $data['remind_me'] == '1' ? true : false; + + $piggyBank->save(); + + return $piggyBank; + } } \ No newline at end of file diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index a06ed505be..656683ff50 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -4,31 +4,19 @@ namespace FireflyIII\Repositories\PiggyBank; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBankRepetition; +use FireflyIII\Models\Reminder; use Illuminate\Support\Collection; +use Carbon\Carbon; /** * Interface PiggyBankRepositoryInterface * * @package FireflyIII\Repositories\PiggyBank */ -interface PiggyBankRepositoryInterface { +interface PiggyBankRepositoryInterface +{ - /** - * @param array $data - * - * @return PiggyBank - */ - public function store(array $data); - - /** - * @param PiggyBank $account - * @param array $data - * - * @return PiggyBank - */ - public function update(PiggyBank $piggyBank, array $data); - /** * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. * @@ -48,4 +36,28 @@ interface PiggyBankRepositoryInterface { * @return PiggyBankPart */ public function createPiggyBankPart(array $data); + + /** + * @param PiggyBank $piggyBank + * @param Carbon $currentStart + * @param Carbon $currentEnd + * + * @return Reminder + */ + public function createReminder(PiggyBank $piggyBank, Carbon $currentStart, Carbon $currentEnd); + + /** + * @param array $data + * + * @return PiggyBank + */ + public function store(array $data); + + /** + * @param PiggyBank $account + * @param array $data + * + * @return PiggyBank + */ + public function update(PiggyBank $piggyBank, array $data); } \ No newline at end of file diff --git a/app/Support/Navigation.php b/app/Support/Navigation.php index c2cfdfb436..7c734e3b9d 100644 --- a/app/Support/Navigation.php +++ b/app/Support/Navigation.php @@ -414,5 +414,47 @@ class Navigation throw new FireflyException('updateStartDate cannot handle $range ' . $range); } + /** + * @param Carbon $theDate + * @param $repeatFreq + * @param int $subtract + * + * @return Carbon + * @throws FireflyException + */ + public function subtractPeriod(Carbon $theDate, $repeatFreq, $subtract = 1) + { + $date = clone $theDate; + + $functionMap = [ + 'daily' => 'subDays', + 'week' => 'subWeeks', + 'weekly' => 'subWeeks', + 'month' => 'subMonths', + 'monthly' => 'subMonths', + 'year' => 'subYears', + 'yearly' => 'subYears', + ]; + $modifierMap = [ + 'quarter' => 3, + 'quarterly' => 3, + 'half-year' => 6, + ]; + if (isset($functionMap[$repeatFreq])) { + $function = $functionMap[$repeatFreq]; + $date->$function($subtract); + + return $date; + } + if (isset($modifierMap[$repeatFreq])) { + $subtract = $subtract * $modifierMap[$repeatFreq]; + $date->subMonths($subtract); + + return $date; + } + + throw new FireflyException('Cannot do subtractPeriod for $repeat_freq ' . $repeatFreq); + } + } \ No newline at end of file diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index f906c5cb6d..46b39b0b1d 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -3,8 +3,10 @@ namespace FireflyIII\Validation; use Auth; +use Carbon\Carbon; use DB; use Illuminate\Validation\Validator; +use Navigation; /** * Class FireflyValidator @@ -32,6 +34,31 @@ class FireflyValidator extends Validator } + public function validatePiggyBankReminder($attribute, $value, $parameters) + { + $array = $this->data; + // no reminder? dont care. + if (!isset($array['remind_me'])) { + return true; + } + + // get or set start date & target date: + $startDate = isset($array['startdate']) ? new Carbon($array['startdate']) : new Carbon; + $targetDate = isset($array['targetdate']) && strlen($array['targetdate']) > 0 ? new Carbon($array['targetdate']) : null; + + // target date is null? reminder period is always good. + if ($array['remind_me'] == '1' && is_null($targetDate)) { + return true; + } + + $nextReminder = Navigation::addPeriod($startDate, $array['reminder'],0); + // reminder is beyond target? + if($nextReminder > $targetDate) { + return false; + } + return true; + } + /** * @param $attribute * @param $value @@ -41,7 +68,11 @@ class FireflyValidator extends Validator */ public function validateUniqueForUser($attribute, $value, $parameters) { - $count = DB::table($parameters[0])->where($parameters[1], $value)->where('id', '!=', $parameters[2])->count(); + $query = DB::table($parameters[0])->where($parameters[1], $value); + if (isset($paramers[2])) { + $query->where('id', '!=', $parameters[2]); + } + $count = $query->count(); if ($count == 0) { return true; } diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index db49422d54..e0e00f3efb 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -20,7 +20,8 @@ return [ "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", "alpha_num" => "The :attribute may only contain letters and numbers.", "array" => "The :attribute must be an array.", - "unique_for_user" => "There already is an entry with this :attribute.", + "unique_for_user" => "There already is an entry with this :attribute.", + 'piggy_bank_reminder' => 'The target date is too close to today to allow reminders.', "before" => "The :attribute must be a date before :date.", "between" => [ "numeric" => "The :attribute must be between :min and :max.",