diff --git a/app/controllers/RepeatedExpenseController.php b/app/controllers/RepeatedExpenseController.php index 6d26891344..58e7242997 100644 --- a/app/controllers/RepeatedExpenseController.php +++ b/app/controllers/RepeatedExpenseController.php @@ -1,5 +1,6 @@ get(); - $expenses->each( - function (\Piggybank $piggyBank) { - // do something with "parts". - $piggyBank->currentRep = $piggyBank->currentRelevantRep(); - if (!is_null($piggyBank->reminder)) { - switch ($piggyBank->reminder) { - default: - throw new FireflyException('Cannot handle "' . $piggyBank->reminder . '" reminders for repeated expenses'); - break; - case 'month': - $start = clone $piggyBank->currentRep->startdate; - $start->startOfMonth(); - $end = clone $piggyBank->currentRep->targetdate; - $end->endOfMonth(); - $piggyBank->parts = $start->diffInMonths($end); - unset($start, $end); - break; - } - - } else { - $piggyBank->parts = 1; - } - - // number of bars: - $piggyBank->barCount = floor(12 / $piggyBank->parts) == 0 ? 1 : floor(12 / $piggyBank->parts); - $amountPerBar = floatval($piggyBank->targetamount) / $piggyBank->parts; - $currentAmount = floatval($amountPerBar); - $bars = []; - $currentDate = clone $piggyBank->currentRep->startdate; - for ($i = 0; $i < $piggyBank->parts; $i++) { - // niet elke keer een andere dinges pakken? om target te redden? - if (!is_null($piggyBank->reminder)) { - $currentDate = \DateKit::addPeriod($currentDate, $piggyBank->reminder, 0); - } - $bars[] = [ - 'amount' => $currentAmount, - 'date' => $currentDate - ]; - - - $currentAmount += $amountPerBar; - } - $piggyBank->bars = $bars; - + function (Piggybank $piggyBank) use ($repository) { + $piggyBank->currentRelevantRep(); + $piggyBank->currentRep = $repository->calculateParts($piggyBank->currentRep); } - ); return View::make('repeatedexpense.index', compact('expenses', 'subTitle')); } + public function show(Piggybank $piggyBank) + { + $subTitle = $piggyBank->name; + $today = Carbon::now(); + + return View::make('repeatedexpense.show', compact('piggyBank', 'today', 'subTitle')); + } + /** * */ diff --git a/app/lib/FireflyIII/Collection/PiggybankPart.php b/app/lib/FireflyIII/Collection/PiggybankPart.php new file mode 100644 index 0000000000..3b198df5db --- /dev/null +++ b/app/lib/FireflyIII/Collection/PiggybankPart.php @@ -0,0 +1,135 @@ +repetition; + } + + /** + * @param \PiggybankRepetition $repetition + */ + public function setRepetition($repetition) + { + $this->repetition = $repetition; + } + + /** + * @return Carbon + */ + public function getStartdate() + { + return $this->startdate; + } + + /** + * @param Carbon $startdate + */ + public function setStartdate($startdate) + { + $this->startdate = $startdate; + } + + /** + * @return Carbon + */ + public function getTargetdate() + { + return $this->targetdate; + } + + /** + * @param Carbon $targetdate + */ + public function setTargetdate($targetdate) + { + $this->targetdate = $targetdate; + } + + public function percentage() + { + if ($this->getCurrentamount() < $this->getAmount()) { + $pct = 0; + // calculate halway point? + if ($this->getAmount() - $this->getCurrentamount() < $this->getAmountPerBar()) { + $left = $this->getCurrentamount() % $this->getAmountPerBar(); + $pct = round($left / $this->getAmountPerBar() * 100); + } + + return $pct; + } else { + return 100; + } + } + + /** + * @return int + */ + public function getCurrentamount() + { + return $this->currentamount; + } + + /** + * @param int $currentamount + */ + public function setCurrentamount($currentamount) + { + $this->currentamount = $currentamount; + } + + /** + * @return int + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param int $amount + */ + public function setAmount($amount) + { + $this->amount = $amount; + } + + /** + * @return mixed + */ + public function getAmountPerBar() + { + return $this->amountPerBar; + } + + /** + * @param mixed $amountPerBar + */ + public function setAmountPerBar($amountPerBar) + { + $this->amountPerBar = $amountPerBar; + } + + +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/RepeatedExpense.php b/app/lib/FireflyIII/Database/RepeatedExpense.php index 2b50bf6bf1..2295c70012 100644 --- a/app/lib/FireflyIII/Database/RepeatedExpense.php +++ b/app/lib/FireflyIII/Database/RepeatedExpense.php @@ -4,9 +4,11 @@ namespace FireflyIII\Database; use Carbon\Carbon; +use FireflyIII\Collection\PiggybankPart; use FireflyIII\Database\Ifaces\CommonDatabaseCalls; use FireflyIII\Database\Ifaces\CUD; use FireflyIII\Database\Ifaces\PiggybankInterface; +use FireflyIII\Exception\FireflyException; use FireflyIII\Exception\NotImplementedException; use Illuminate\Support\Collection; use Illuminate\Support\MessageBag; @@ -24,6 +26,212 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggybankInterface $this->setUser(\Auth::user()); } + /** + * Based on the piggy bank, the reminder-setting and + * other variables this method tries to divide the piggy bank into equal parts. Each is + * accommodated by a reminder (if everything goes to plan). + * + * @return \PiggybankRepetition + */ + public function calculateParts(\PiggybankRepetition $repetition) + { + \Log::debug('NOW in calculateParts()'); + \Log::debug('Repetition id is ' . $repetition->id); + /** @var \Piggybank $piggyBank */ + $piggyBank = $repetition->piggybank()->first(); + \Log::debug('connected piggy bank is: ' . $piggyBank->name . ' (#' . $piggyBank->id . ')'); + + /* + * If no reminders are set, the repetition is split in exactly one part: + */ + if (is_null($piggyBank->reminder)) { + $parts = 1; + } else { + /* + * Number of parts is the number of [reminder period]s between + * the start date and the target date + */ + /** @var Carbon $start */ + $start = clone $repetition->startdate; + /** @var Carbon $target */ + $target = clone $repetition->targetdate; + + switch ($piggyBank->reminder) { + default: + throw new FireflyException('Cannot handle "' . $piggyBank->reminder . '" reminders for repeated expenses (calculateParts)'); + break; + case 'week': + $parts = $start->diffInWeeks($target); + break; + case 'month': + $parts = $start->diffInMonths($target); + break; + case 'quarter': + $parts = ceil($start->diffInMonths($target) / 3); + break; + case 'year': + $parts = $start->diffInYears($target); + break; + } + $parts = $parts < 1 ? 1 : $parts; + unset($start, $target); + + + // /* + // * Otherwise, FF3 splits by the difference in time and the amount + // * of reminders the user wants. + // */ + // switch ($piggyBank->reminder) { + // default: + // throw new FireflyException('Cannot handle "' . $piggyBank->reminder . '" reminders for repeated expenses (calculateParts)'); + // break; + // case 'week': + // $start = clone $repetition->startdate; + // $start->startOfWeek(); + // $end = clone $repetition->targetdate; + // $end->endOfWeek(); + // $parts = $start->diffInWeeks($end); + // unset($start, $end); + // break; + // case 'month': + // $start = clone $repetition->startdate; + // $start->startOfMonth(); + // $end = clone $repetition->targetdate; + // $end->endOfMonth(); + // $parts = $start->diffInMonths($end); + // unset($start, $end); + // break; + // } + } + $amountPerBar = floatval($piggyBank->targetamount) / $parts; + $currentAmount = floatval($amountPerBar); + $currentStart = clone $repetition->startdate; + $currentTarget = clone $repetition->targetdate; + $bars = new Collection; + + // if($parts > 12) { + // $parts = 12; + // $currentStart = \DateKit::startOfPeriod(Carbon::now(), $piggyBank->reminder); + // $currentEnd = \DateKit::endOfPeriod($currentEnd, $piggyBank->reminder); + // } + + for ($i = 0; $i < $parts; $i++) { + /* + * Jump one month ahead after the first instance: + */ + // if ($i > 0) { + // $currentStart = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); + // /* + // * Jump to the start of the period too: + // */ + // $currentStart = \DateKit::startOfPeriod($currentStart, $piggyBank->reminder); + // + // } + + + /* + * Move the current start to the actual start of + * the [period] once the first iteration has passed. + */ + // if ($i != 0) { + // $currentStart = \DateKit::startOfPeriod($currentStart, $piggyBank->reminder); + // } + // if($i == 0 && !is_null($piggyBank->reminder)) { + // $currentEnd = \DateKit::startOfPeriod($currentStart, $piggyBank->reminder); + // $currentEnd = \DateKit::endOfPeriod($currentEnd, $piggyBank->reminder); + // } + + $part = new PiggybankPart; + $part->setRepetition($repetition); + $part->setAmount($currentAmount); + $part->setAmountPerBar($amountPerBar); + $part->setCurrentamount($repetition->currentamount); + $part->setStartdate($currentStart); + $part->setTargetdate($currentTarget); + + // if (!is_null($piggyBank->reminder)) { + // $currentStart = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); + // $currentEnd = \DateKit::endOfPeriod($currentStart, $piggyBank->reminder); + // } + + + $bars->push($part); + $currentAmount += $amountPerBar; + } + $repetition->bars = $bars; + + return $repetition; + exit; + + + $repetition->hello = 'World!'; + + return $repetition; + + $return = new Collection; + $repetitions = $piggyBank->piggybankrepetitions()->get(); + /** @var \PiggybankRepetition $repetition */ + foreach ($repetitions as $repetition) { + + + if (is_null($piggyBank->reminder)) { + // simple, one part "repetition". + $part = new PiggybankPart; + $part->setRepetition($repetition); + } else { + $part = new PiggybankPart; + } + + + // end! + $return->push($part); + } + + exit; + + return $return; + $piggyBank->currentRelevantRep(); // get the current relevant repetition. + if (!is_null($piggyBank->reminder)) { + switch ($piggyBank->reminder) { + default: + throw new FireflyException('Cannot handle "' . $piggyBank->reminder . '" reminders for repeated expenses'); + break; + case 'month': + $start = clone $piggyBank->currentRep->startdate; + $start->startOfMonth(); + $end = clone $piggyBank->currentRep->targetdate; + $end->endOfMonth(); + $piggyBank->parts = $start->diffInMonths($end); + unset($start, $end); + break; + } + + } else { + $piggyBank->parts = 1; + } + + // number of bars: + $piggyBank->barCount = floor(12 / $piggyBank->parts) == 0 ? 1 : floor(12 / $piggyBank->parts); + $amountPerBar = floatval($piggyBank->targetamount) / $piggyBank->parts; + $currentAmount = floatval($amountPerBar); + $bars = []; + $currentStart = clone $piggyBank->currentRep->startdate; + for ($i = 0; $i < $piggyBank->parts; $i++) { + // niet elke keer een andere dinges pakken? om target te redden? + if (!is_null($piggyBank->reminder)) { + $currentStart = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); + } + $bars[] = [ + 'amount' => $currentAmount, + 'date' => $currentStart + ]; + + + $currentAmount += $amountPerBar; + } + $piggyBank->bars = $bars; + } + /** * @param Ardent $model * @@ -119,6 +327,10 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggybankInterface } catch (\Exception $e) { $errors->add('targetdate', 'Invalid date.'); } + $diff = Carbon::now()->diff(new Carbon($model['targetdate'])); + if ($diff->days > 365) { + $errors->add('targetdate', 'First target date should a a year or less from now.'); + } } else { $errors->add('targetdate', 'Invalid target date.'); } diff --git a/app/lib/FireflyIII/Shared/Toolkit/Date.php b/app/lib/FireflyIII/Shared/Toolkit/Date.php index f9857a8547..5725db90ad 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Date.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Date.php @@ -82,12 +82,14 @@ class Date case 'monthly': $currentEnd->addMonth()->subDay(); break; + case 'quarter': case 'quarterly': $currentEnd->addMonths(3)->subDay(); break; case 'half-year': $currentEnd->addMonths(6)->subDay(); break; + case 'year': case 'yearly': $currentEnd->addYear()->subDay(); break; @@ -154,6 +156,7 @@ class Date $date->addMonths(6); } break; + case 'year': case 'yearly': $date->startOfYear(); break; diff --git a/app/lib/FireflyIII/Shared/Toolkit/Reminders.php b/app/lib/FireflyIII/Shared/Toolkit/Reminders.php index 453f6e7926..040c9cccd6 100644 --- a/app/lib/FireflyIII/Shared/Toolkit/Reminders.php +++ b/app/lib/FireflyIII/Shared/Toolkit/Reminders.php @@ -71,8 +71,13 @@ class Reminders /** @var \FireflyIII\Database\Piggybank $repository */ $repository = \App::make('FireflyIII\Database\Piggybank'); + /** @var \FireflyIII\Database\Piggybank $repeatedRepository */ + $repeatedRepository = \App::make('FireflyIII\Database\RepeatedExpense'); + /** @var Collection $piggybanks */ - $piggybanks = $repository->get(); + $piggybanks = $repository->get()->merge($repeatedRepository->get()); + + $set = $piggybanks->filter( function (\Piggybank $piggybank) { if (!is_null($piggybank->reminder)) { diff --git a/app/models/Piggybank.php b/app/models/Piggybank.php index e69a85d689..291e96577f 100644 --- a/app/models/Piggybank.php +++ b/app/models/Piggybank.php @@ -42,7 +42,7 @@ use LaravelBook\Ardent\Ardent as Ardent; * @method static \Illuminate\Database\Query\Builder|\Piggybank whereReminderSkip($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereOrder($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereRemindMe($value) - * @property-read \Illuminate\Database\Eloquent\Collection|\Reminder[] $reminders + * @property-read \Illuminate\Database\Eloquent\Collection|\Reminder[] $reminders */ class Piggybank extends Ardent { @@ -56,7 +56,7 @@ class Piggybank extends Ardent 'rep_length' => 'in:day,week,month,quarter,year', // how long is the period? 'rep_every' => 'required|min:1|max:100', // how often does it repeat? every 3 years. 'rep_times' => 'min:1|max:100', // how many times do you want to save this amount? eg. 3 times - 'reminder' => 'in:day,week,month,year', // want a reminder to put money in this? + 'reminder' => 'in:day,week,quarter,month,year', // want a reminder to put money in this? 'reminder_skip' => 'required|min:0|max:100', // every week? every 2 months? 'remind_me' => 'required|boolean', 'order' => 'required:min:1', // not yet used. ]; @@ -77,16 +77,12 @@ class Piggybank extends Ardent * * @return int */ - public function amountPerReminder() { + public function amountPerReminder() + { return 0; } - public function reminders() - { - return $this->morphMany('Reminder', 'remindersable'); - } - /** * TODO remove this method in favour of something in the FireflyIII libraries. * @@ -130,37 +126,44 @@ class Piggybank extends Ardent return $this->currentRep; } if ($this->repeats == 0) { - $rep = $this->piggybankrepetitions()->first(); + $rep = $this->piggybankrepetitions()->first(['piggybank_repetitions.*']); $this->currentRep = $rep; - return $rep; } else { - $query = $this->piggybankrepetitions()->where( + $query = $this->piggybankrepetitions()->where( function ($q) { $q->where( function ($q) { - $today = new Carbon; - $q->whereNull('startdate'); - $q->orWhere('startdate', '<=', $today->format('Y-m-d')); + + $q->where( + function ($q) { + $today = new Carbon; + $q->whereNull('startdate'); + $q->orWhere('startdate', '<=', $today->format('Y-m-d')); + } + )->where( + function ($q) { + $today = new Carbon; + $q->whereNull('targetdate'); + $q->orWhere('targetdate', '>=', $today->format('Y-m-d')); + } + ); } - )->where( + )->orWhere( function ($q) { $today = new Carbon; - $q->whereNull('targetdate'); - $q->orWhere('targetdate', '>=', $today->format('Y-m-d')); + $q->where('startdate', '>=', $today->format('Y-m-d')); + $q->where('targetdate', '>=', $today->format('Y-m-d')); } ); + } - )->orWhere( - function ($q) { - $today = new Carbon; - $q->where('startdate', '>=', $today->format('Y-m-d')); - $q->where('targetdate', '>=', $today->format('Y-m-d')); - } - )->orderBy('startdate', 'ASC'); - $result = $query->first(); + ) + ->orderBy('startdate', 'ASC'); + $result = $query->first(['piggybank_repetitions.*']); $this->currentRep = $result; + \Log::debug('Found relevant rep in currentRelevantRep(): ' . $result->id); return $result; } @@ -192,6 +195,11 @@ class Piggybank extends Ardent return $this->hasMany('PiggybankEvent'); } + public function reminders() + { + return $this->morphMany('Reminder', 'remindersable'); + } + /** * TODO remove this method in favour of something in the FireflyIII libraries. * diff --git a/app/routes.php b/app/routes.php index 93e667e22b..d11b2b3e4a 100644 --- a/app/routes.php +++ b/app/routes.php @@ -103,13 +103,27 @@ Route::bind( 'piggybank', function ($value, $route) { if (Auth::check()) { return Piggybank:: - where('piggybanks.id', $value)->leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where('accounts.user_id', Auth::user()->id) - ->first(['piggybanks.*']); + where('piggybanks.id', $value) + ->leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id') + ->where('accounts.user_id', Auth::user()->id) + ->where('repeats',0)->first(['piggybanks.*']); } return null; } ); +Route::bind( + 'repeated', function ($value, $route) { + if (Auth::check()) { + return Piggybank:: + where('piggybanks.id', $value) + ->leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id') + ->where('accounts.user_id', Auth::user()->id) + ->where('repeats',1)->first(['piggybanks.*']); + } + return null; + } +); // protected routes: Route::group( diff --git a/app/views/accounts/index.blade.php b/app/views/accounts/index.blade.php index ba78cd68d8..54a5734050 100644 --- a/app/views/accounts/index.blade.php +++ b/app/views/accounts/index.blade.php @@ -21,9 +21,7 @@ -
Name | diff --git a/app/views/repeatedexpense/index.blade.php b/app/views/repeatedexpense/index.blade.php index 1b285352f2..eb8765a4ee 100644 --- a/app/views/repeatedexpense/index.blade.php +++ b/app/views/repeatedexpense/index.blade.php @@ -14,14 +14,36 @@ @foreach($expenses as $entry) +currentRep->bars->count()) == 0 ? 1 : floor(12 / $entry->currentRep->bars->count()); +?>
---|