diff --git a/app/Http/Controllers/Bill/IndexController.php b/app/Http/Controllers/Bill/IndexController.php index 73589644d5..34f27d8252 100644 --- a/app/Http/Controllers/Bill/IndexController.php +++ b/app/Http/Controllers/Bill/IndexController.php @@ -57,7 +57,7 @@ class IndexController extends Controller $this->middleware( function ($request, $next) { - app('view')->share('title', (string) trans('firefly.bills')); + app('view')->share('title', (string)trans('firefly.bills')); app('view')->share('mainTitleIcon', 'fa-calendar-o'); $this->repository = app(BillRepositoryInterface::class); @@ -73,27 +73,26 @@ class IndexController extends Controller { $this->cleanupObjectGroups(); $this->repository->correctOrder(); - $start = session('start'); - $end = session('end'); - $collection = $this->repository->getBills(); - $total = $collection->count(); + $start = session('start'); + $end = session('end'); + $collection = $this->repository->getBills(); + $total = $collection->count(); - - $parameters = new ParameterBag(); + $parameters = new ParameterBag(); // sub one day from temp start so the last paid date is one day before it should be. - $tempStart = clone $start; + $tempStart = clone $start; // 2023-06-23 do not sub one day from temp start, fix is in BillTransformer::payDates instead // $tempStart->subDay(); // enrich /** @var User $admin */ - $admin = auth()->user(); - $enrichment = new SubscriptionEnrichment(); + $admin = auth()->user(); + $enrichment = new SubscriptionEnrichment(); $enrichment->setUser($admin); $enrichment->setStart($tempStart); $enrichment->setEnd($end); - $collection = $enrichment->enrich($collection); + $collection = $enrichment->enrich($collection); $parameters->set('start', $tempStart); @@ -106,21 +105,21 @@ class IndexController extends Controller $transformer->setParameters($parameters); // loop all bills, convert to array and add rules and stuff. - $rules = $this->repository->getRulesForBills($collection); + $rules = $this->repository->getRulesForBills($collection); // make bill groups: - $bills = [ + $bills = [ 0 => [ // the index is the order, not the ID. - 'object_group_id' => 0, - 'object_group_title' => (string) trans('firefly.default_group_title_name'), - 'bills' => [], + 'object_group_id' => 0, + 'object_group_title' => (string)trans('firefly.default_group_title_name'), + 'bills' => [], ], ]; /** @var Bill $bill */ foreach ($collection as $bill) { - $array = $transformer->transform($bill); - $groupOrder = (int) $array['object_group_order']; + $array = $transformer->transform($bill); + $groupOrder = (int)$array['object_group_order']; // make group array if necessary: $bills[$groupOrder] ??= [ 'object_group_id' => $array['object_group_id'], @@ -142,9 +141,9 @@ class IndexController extends Controller ksort($bills); // summarise per currency / per group. - $sums = $this->getSums($bills); - $totals = $this->getTotals($sums); - $today = now()->startOfDay(); + $sums = $this->getSums($bills); + $totals = $this->getTotals($sums); + $today = now()->startOfDay(); return view('bills.index', compact('bills', 'sums', 'total', 'totals', 'today')); } @@ -165,7 +164,7 @@ class IndexController extends Controller continue; } - $currencyId = $bill['currency_id']; + $currencyId = $bill['currency_id']; $sums[$groupOrder][$currencyId] ??= [ 'currency_id' => $currencyId, 'currency_code' => $bill['currency_code'], @@ -173,16 +172,28 @@ class IndexController extends Controller 'currency_symbol' => $bill['currency_symbol'], 'currency_decimal_places' => $bill['currency_decimal_places'], 'avg' => '0', + 'total_left_to_pay' => '0', 'period' => $range, 'per_period' => '0', ]; // only fill in avg when bill is active. if (null !== $bill['next_expected_match']) { - $avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2'); - $avg = bcmul($avg, (string) count($bill['pay_dates'])); + $avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2'); + $avg = bcmul($avg, (string)count($bill['pay_dates'])); $sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg); } + // only fill in total_left_to_pay when bill is not yet paid. + if (count($bill['paid_dates']) < count($bill['pay_dates'])) { + $count = count($bill['pay_dates']) - count($bill['paid_dates']); + if ($count > 0) { + $avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2'); + $avg = bcmul($avg, (string)$count); + $sums[$groupOrder][$currencyId]['total_left_to_pay'] = bcadd($sums[$groupOrder][$currencyId]['total_left_to_pay'], $avg); + } + } + + // fill in per period regardless: $sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range)); } @@ -193,7 +204,7 @@ class IndexController extends Controller private function amountPerPeriod(array $bill, string $range): string { - $avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2'); + $avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2'); app('log')->debug(sprintf('Amount per period for bill #%d "%s"', $bill['id'], $bill['name'])); app('log')->debug(sprintf('Average is %s', $avg)); @@ -206,11 +217,11 @@ class IndexController extends Controller 'weekly' => '52.17', 'daily' => '365.24', ]; - $yearAmount = bcmul($avg, bcdiv($multiplies[$bill['repeat_freq']], (string) ($bill['skip'] + 1))); - app('log')->debug(sprintf('Amount per year is %s (%s * %s / %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']], (string) ($bill['skip'] + 1))); + $yearAmount = bcmul($avg, bcdiv($multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1))); + app('log')->debug(sprintf('Amount per year is %s (%s * %s / %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1))); // per period: - $division = [ + $division = [ '1Y' => '1', '6M' => '2', '3M' => '4', @@ -225,7 +236,7 @@ class IndexController extends Controller 'last90' => '4', 'last365' => '1', ]; - $perPeriod = bcdiv($yearAmount, $division[$range]); + $perPeriod = bcdiv($yearAmount, $division[$range]); app('log')->debug(sprintf('Amount per %s is %s (%s / %s)', $range, $perPeriod, $yearAmount, $division[$range])); @@ -244,11 +255,11 @@ class IndexController extends Controller */ foreach ($sums as $array) { /** - * @var int $currencyId + * @var int $currencyId * @var array $entry */ foreach ($array as $currencyId => $entry) { - $totals[$currencyId] ??= [ + $totals[$currencyId] ??= [ 'currency_id' => $currencyId, 'currency_code' => $entry['currency_code'], 'currency_name' => $entry['currency_name'], @@ -258,8 +269,8 @@ class IndexController extends Controller 'period' => $entry['period'], 'per_period' => '0', ]; - $totals[$currencyId]['avg'] = bcadd($totals[$currencyId]['avg'], (string) $entry['avg']); - $totals[$currencyId]['per_period'] = bcadd($totals[$currencyId]['per_period'], (string) $entry['per_period']); + $totals[$currencyId]['avg'] = bcadd($totals[$currencyId]['avg'], (string)$entry['avg']); + $totals[$currencyId]['per_period'] = bcadd($totals[$currencyId]['per_period'], (string)$entry['per_period']); } } @@ -271,8 +282,8 @@ class IndexController extends Controller */ public function setOrder(Request $request, Bill $bill): JsonResponse { - $objectGroupTitle = (string) $request->get('objectGroupTitle'); - $newOrder = (int) $request->get('order'); + $objectGroupTitle = (string)$request->get('objectGroupTitle'); + $newOrder = (int)$request->get('order'); $this->repository->setOrder($bill, $newOrder); if ('' !== $objectGroupTitle) { $this->repository->setObjectGroup($bill, $objectGroupTitle); diff --git a/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php b/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php index 2d12ff5dbd..e143208f54 100644 --- a/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php +++ b/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php @@ -56,6 +56,7 @@ class SubscriptionEnrichment implements EnrichmentInterface $this->collectPaidDates(); $this->collectPayDates(); + // TODO clean me up. $notes = $this->notes; diff --git a/app/Support/Models/BillDateCalculator.php b/app/Support/Models/BillDateCalculator.php index 71ffa170aa..3d49c867a3 100644 --- a/app/Support/Models/BillDateCalculator.php +++ b/app/Support/Models/BillDateCalculator.php @@ -110,8 +110,8 @@ class BillDateCalculator $currentStart = clone $nextExpectedMatch; ++$loop; - if ($loop > 12) { - Log::debug('Loop is more than 12, so we break.'); + if ($loop > 31) { + Log::debug('Loop is more than 31, so we break.'); break; } diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 66d0e6e6b9..2cb6eff9a1 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -1864,6 +1864,7 @@ return [ 'remove_budgeted_amount' => 'Remove budgeted amount in :currency', // bills: + 'left_to_pay_active_bills' => 'active, expected and not yet paid subscriptions', 'left_to_pay_lc' => 'left to pay', 'less_than_expected' => 'less than expected', 'more_than_expected' => 'more than expected', diff --git a/resources/views/budgets/show.twig b/resources/views/budgets/show.twig index 8eeba0cfc6..8f3c53aefa 100644 --- a/resources/views/budgets/show.twig +++ b/resources/views/budgets/show.twig @@ -158,8 +158,8 @@