mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-30 02:26:58 +00:00
Fix #9650
This commit is contained in:
@@ -57,7 +57,7 @@ class IndexController extends Controller
|
|||||||
|
|
||||||
$this->middleware(
|
$this->middleware(
|
||||||
function ($request, $next) {
|
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');
|
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||||
$this->repository = app(BillRepositoryInterface::class);
|
$this->repository = app(BillRepositoryInterface::class);
|
||||||
|
|
||||||
@@ -73,27 +73,26 @@ class IndexController extends Controller
|
|||||||
{
|
{
|
||||||
$this->cleanupObjectGroups();
|
$this->cleanupObjectGroups();
|
||||||
$this->repository->correctOrder();
|
$this->repository->correctOrder();
|
||||||
$start = session('start');
|
$start = session('start');
|
||||||
$end = session('end');
|
$end = session('end');
|
||||||
$collection = $this->repository->getBills();
|
$collection = $this->repository->getBills();
|
||||||
$total = $collection->count();
|
$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.
|
// 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
|
// 2023-06-23 do not sub one day from temp start, fix is in BillTransformer::payDates instead
|
||||||
// $tempStart->subDay();
|
// $tempStart->subDay();
|
||||||
|
|
||||||
// enrich
|
// enrich
|
||||||
/** @var User $admin */
|
/** @var User $admin */
|
||||||
$admin = auth()->user();
|
$admin = auth()->user();
|
||||||
$enrichment = new SubscriptionEnrichment();
|
$enrichment = new SubscriptionEnrichment();
|
||||||
$enrichment->setUser($admin);
|
$enrichment->setUser($admin);
|
||||||
$enrichment->setStart($tempStart);
|
$enrichment->setStart($tempStart);
|
||||||
$enrichment->setEnd($end);
|
$enrichment->setEnd($end);
|
||||||
$collection = $enrichment->enrich($collection);
|
$collection = $enrichment->enrich($collection);
|
||||||
|
|
||||||
|
|
||||||
$parameters->set('start', $tempStart);
|
$parameters->set('start', $tempStart);
|
||||||
@@ -106,21 +105,21 @@ class IndexController extends Controller
|
|||||||
$transformer->setParameters($parameters);
|
$transformer->setParameters($parameters);
|
||||||
|
|
||||||
// loop all bills, convert to array and add rules and stuff.
|
// loop all bills, convert to array and add rules and stuff.
|
||||||
$rules = $this->repository->getRulesForBills($collection);
|
$rules = $this->repository->getRulesForBills($collection);
|
||||||
|
|
||||||
// make bill groups:
|
// make bill groups:
|
||||||
$bills = [
|
$bills = [
|
||||||
0 => [ // the index is the order, not the ID.
|
0 => [ // the index is the order, not the ID.
|
||||||
'object_group_id' => 0,
|
'object_group_id' => 0,
|
||||||
'object_group_title' => (string) trans('firefly.default_group_title_name'),
|
'object_group_title' => (string)trans('firefly.default_group_title_name'),
|
||||||
'bills' => [],
|
'bills' => [],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var Bill $bill */
|
/** @var Bill $bill */
|
||||||
foreach ($collection as $bill) {
|
foreach ($collection as $bill) {
|
||||||
$array = $transformer->transform($bill);
|
$array = $transformer->transform($bill);
|
||||||
$groupOrder = (int) $array['object_group_order'];
|
$groupOrder = (int)$array['object_group_order'];
|
||||||
// make group array if necessary:
|
// make group array if necessary:
|
||||||
$bills[$groupOrder] ??= [
|
$bills[$groupOrder] ??= [
|
||||||
'object_group_id' => $array['object_group_id'],
|
'object_group_id' => $array['object_group_id'],
|
||||||
@@ -142,9 +141,9 @@ class IndexController extends Controller
|
|||||||
ksort($bills);
|
ksort($bills);
|
||||||
|
|
||||||
// summarise per currency / per group.
|
// summarise per currency / per group.
|
||||||
$sums = $this->getSums($bills);
|
$sums = $this->getSums($bills);
|
||||||
$totals = $this->getTotals($sums);
|
$totals = $this->getTotals($sums);
|
||||||
$today = now()->startOfDay();
|
$today = now()->startOfDay();
|
||||||
|
|
||||||
return view('bills.index', compact('bills', 'sums', 'total', 'totals', 'today'));
|
return view('bills.index', compact('bills', 'sums', 'total', 'totals', 'today'));
|
||||||
}
|
}
|
||||||
@@ -165,7 +164,7 @@ class IndexController extends Controller
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$currencyId = $bill['currency_id'];
|
$currencyId = $bill['currency_id'];
|
||||||
$sums[$groupOrder][$currencyId] ??= [
|
$sums[$groupOrder][$currencyId] ??= [
|
||||||
'currency_id' => $currencyId,
|
'currency_id' => $currencyId,
|
||||||
'currency_code' => $bill['currency_code'],
|
'currency_code' => $bill['currency_code'],
|
||||||
@@ -173,16 +172,28 @@ class IndexController extends Controller
|
|||||||
'currency_symbol' => $bill['currency_symbol'],
|
'currency_symbol' => $bill['currency_symbol'],
|
||||||
'currency_decimal_places' => $bill['currency_decimal_places'],
|
'currency_decimal_places' => $bill['currency_decimal_places'],
|
||||||
'avg' => '0',
|
'avg' => '0',
|
||||||
|
'total_left_to_pay' => '0',
|
||||||
'period' => $range,
|
'period' => $range,
|
||||||
'per_period' => '0',
|
'per_period' => '0',
|
||||||
];
|
];
|
||||||
|
|
||||||
// only fill in avg when bill is active.
|
// only fill in avg when bill is active.
|
||||||
if (null !== $bill['next_expected_match']) {
|
if (null !== $bill['next_expected_match']) {
|
||||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
$avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2');
|
||||||
$avg = bcmul($avg, (string) count($bill['pay_dates']));
|
$avg = bcmul($avg, (string)count($bill['pay_dates']));
|
||||||
$sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg);
|
$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:
|
// fill in per period regardless:
|
||||||
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
|
$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
|
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('Amount per period for bill #%d "%s"', $bill['id'], $bill['name']));
|
||||||
app('log')->debug(sprintf('Average is %s', $avg));
|
app('log')->debug(sprintf('Average is %s', $avg));
|
||||||
@@ -206,11 +217,11 @@ class IndexController extends Controller
|
|||||||
'weekly' => '52.17',
|
'weekly' => '52.17',
|
||||||
'daily' => '365.24',
|
'daily' => '365.24',
|
||||||
];
|
];
|
||||||
$yearAmount = bcmul($avg, bcdiv($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)));
|
app('log')->debug(sprintf('Amount per year is %s (%s * %s / %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1)));
|
||||||
|
|
||||||
// per period:
|
// per period:
|
||||||
$division = [
|
$division = [
|
||||||
'1Y' => '1',
|
'1Y' => '1',
|
||||||
'6M' => '2',
|
'6M' => '2',
|
||||||
'3M' => '4',
|
'3M' => '4',
|
||||||
@@ -225,7 +236,7 @@ class IndexController extends Controller
|
|||||||
'last90' => '4',
|
'last90' => '4',
|
||||||
'last365' => '1',
|
'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]));
|
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) {
|
foreach ($sums as $array) {
|
||||||
/**
|
/**
|
||||||
* @var int $currencyId
|
* @var int $currencyId
|
||||||
* @var array $entry
|
* @var array $entry
|
||||||
*/
|
*/
|
||||||
foreach ($array as $currencyId => $entry) {
|
foreach ($array as $currencyId => $entry) {
|
||||||
$totals[$currencyId] ??= [
|
$totals[$currencyId] ??= [
|
||||||
'currency_id' => $currencyId,
|
'currency_id' => $currencyId,
|
||||||
'currency_code' => $entry['currency_code'],
|
'currency_code' => $entry['currency_code'],
|
||||||
'currency_name' => $entry['currency_name'],
|
'currency_name' => $entry['currency_name'],
|
||||||
@@ -258,8 +269,8 @@ class IndexController extends Controller
|
|||||||
'period' => $entry['period'],
|
'period' => $entry['period'],
|
||||||
'per_period' => '0',
|
'per_period' => '0',
|
||||||
];
|
];
|
||||||
$totals[$currencyId]['avg'] = bcadd($totals[$currencyId]['avg'], (string) $entry['avg']);
|
$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]['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
|
public function setOrder(Request $request, Bill $bill): JsonResponse
|
||||||
{
|
{
|
||||||
$objectGroupTitle = (string) $request->get('objectGroupTitle');
|
$objectGroupTitle = (string)$request->get('objectGroupTitle');
|
||||||
$newOrder = (int) $request->get('order');
|
$newOrder = (int)$request->get('order');
|
||||||
$this->repository->setOrder($bill, $newOrder);
|
$this->repository->setOrder($bill, $newOrder);
|
||||||
if ('' !== $objectGroupTitle) {
|
if ('' !== $objectGroupTitle) {
|
||||||
$this->repository->setObjectGroup($bill, $objectGroupTitle);
|
$this->repository->setObjectGroup($bill, $objectGroupTitle);
|
||||||
|
@@ -56,6 +56,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
|
|||||||
$this->collectPaidDates();
|
$this->collectPaidDates();
|
||||||
$this->collectPayDates();
|
$this->collectPayDates();
|
||||||
|
|
||||||
|
|
||||||
// TODO clean me up.
|
// TODO clean me up.
|
||||||
|
|
||||||
$notes = $this->notes;
|
$notes = $this->notes;
|
||||||
|
@@ -110,8 +110,8 @@ class BillDateCalculator
|
|||||||
$currentStart = clone $nextExpectedMatch;
|
$currentStart = clone $nextExpectedMatch;
|
||||||
|
|
||||||
++$loop;
|
++$loop;
|
||||||
if ($loop > 12) {
|
if ($loop > 31) {
|
||||||
Log::debug('Loop is more than 12, so we break.');
|
Log::debug('Loop is more than 31, so we break.');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -1864,6 +1864,7 @@ return [
|
|||||||
'remove_budgeted_amount' => 'Remove budgeted amount in :currency',
|
'remove_budgeted_amount' => 'Remove budgeted amount in :currency',
|
||||||
|
|
||||||
// bills:
|
// bills:
|
||||||
|
'left_to_pay_active_bills' => 'active, expected and not yet paid subscriptions',
|
||||||
'left_to_pay_lc' => 'left to pay',
|
'left_to_pay_lc' => 'left to pay',
|
||||||
'less_than_expected' => 'less than expected',
|
'less_than_expected' => 'less than expected',
|
||||||
'more_than_expected' => 'more than expected',
|
'more_than_expected' => 'more than expected',
|
||||||
|
@@ -158,8 +158,8 @@
|
|||||||
<td style="width:33%;">{{ 'amount'|_ }}</td>
|
<td style="width:33%;">{{ 'amount'|_ }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ formatAmountBySymbol(limit.amount, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }}
|
{{ formatAmountBySymbol(limit.amount, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }}
|
||||||
{% if convertToPrimary and 0 != limit.pc_amount %}
|
{% if convertToPrimary and null != limit.native_amount %}
|
||||||
({{ formatAmountBySymbol(limit.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
|
({{ formatAmountBySymbol(limit.native_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@@ -189,6 +189,21 @@
|
|||||||
<td class="hidden-sm hidden-xs"> </td><!-- repeats -->
|
<td class="hidden-sm hidden-xs"> </td><!-- repeats -->
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if '0' != sum.total_left_to_pay %}
|
||||||
|
<tr>
|
||||||
|
<td class="hidden-sm hidden-xs"> </td> <!-- handle -->
|
||||||
|
<td class="hidden-sm hidden-xs"> </td> <!-- buttons -->
|
||||||
|
<td colspan="2" style="text-align: right;"> <!-- title -->
|
||||||
|
<small>{{ 'sum'|_ }} ({{ sum.currency_name }}) ({{ 'left_to_pay_active_bills'|_ }})</small>
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;"> <!-- amount -->
|
||||||
|
{{ formatAmountBySymbol(sum.total_left_to_pay, sum.currency_symbol, sum.currency_decimal_places) }}
|
||||||
|
</td>
|
||||||
|
<td> </td> <!-- paid in period -->
|
||||||
|
<td class="hidden-sm hidden-xs"> </td> <!-- next expected match -->
|
||||||
|
<td class="hidden-sm hidden-xs"> </td><!-- repeats -->
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% if '0' != sum.per_period %}
|
{% if '0' != sum.per_period %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="hidden-sm hidden-xs"> </td> <!-- handle -->
|
<td class="hidden-sm hidden-xs"> </td> <!-- handle -->
|
||||||
|
Reference in New Issue
Block a user