106 lines
4.4 KiB
PHP
106 lines
4.4 KiB
PHP
<?php
|
||
/**
|
||
* @package Bicycle
|
||
* @author Egor Isaev
|
||
* @description IndexController.php
|
||
* @copyright (c) 03/06/2026
|
||
*/
|
||
|
||
namespace App\Controller;
|
||
|
||
use App\Repositories\AccountRepository;
|
||
use App\Repositories\BudgetRepository;
|
||
use App\Repositories\CategoryRepository;
|
||
use App\Repositories\GoalRepository;
|
||
use App\Repositories\TransactionRepository;
|
||
use App\Repositories\UserRepository;
|
||
use Services\Auth;
|
||
use System\Classes\Controller;
|
||
use System\Classes\MyException;
|
||
|
||
/**
|
||
* Дашборд — главная страница после входа (защищена, см. $_auth_protection).
|
||
*/
|
||
class IndexController extends Controller
|
||
{
|
||
protected bool $_auth_protection = true;
|
||
|
||
/**
|
||
* @return string
|
||
* @throws MyException
|
||
*/
|
||
public function indexAction(): string
|
||
{
|
||
$auth_user = Auth::instance()->getUser();
|
||
$user = (new UserRepository())->getByLogin($auth_user['login']);
|
||
|
||
$account_repo = new AccountRepository();
|
||
|
||
$accounts = $user ? $account_repo->getList('*', ['user_id' => $user->id, 'is_delete' => 0], '`order`') : [];
|
||
$archived_accounts = $user ? $account_repo->getList('*', ['user_id' => $user->id, 'is_delete' => 1], 'title') : [];
|
||
|
||
$total = array_sum(array_map(
|
||
static fn ($account) => $account->include_in_total && $account->currency === 'RUB' ? (float)$account->summa : 0,
|
||
$accounts ?: []
|
||
));
|
||
|
||
// «Всего по всем счетам» — без фильтра include_in_total, для строки под «Доступно сейчас»
|
||
// (см. дизайн-хендофф App/design_handoff_personal_finance). Валютные счета — та же
|
||
// сознательная недоделка, что и у $total выше: без Services\CurrencyRate конвертировать
|
||
// не во что, поэтому считаем только RUB (не показываем непересчитанную сумму как есть).
|
||
$total_all = array_sum(array_map(
|
||
static fn ($account) => $account->currency === 'RUB' ? (float)$account->summa : 0,
|
||
$accounts ?: []
|
||
));
|
||
|
||
$month = (int)date('n');
|
||
$year = (int)date('Y');
|
||
|
||
$category_repo = new CategoryRepository();
|
||
$budget_repo = new BudgetRepository();
|
||
|
||
$tree = $user ? $category_repo->getTree($user->id) : [];
|
||
$plan_month = $user ? array_map(
|
||
static fn ($months) => $months[$month]['plan_summ'] ?? 0.0,
|
||
$budget_repo->getYear($user->id, $year)
|
||
) : [];
|
||
|
||
// Факт за месяц — реальные transactions (таблица/репозиторий уже есть, UI для их ввода
|
||
// пока нет, поэтому в живой БД сумма обычно 0 — это корректный факт, не заглушка).
|
||
$fact_month = $user ? (new TransactionRepository())->getMonthActualByCategory($user->id, $year, $month) : [];
|
||
|
||
// % бюджета по расходам за месяц — план/факт только по expense-статьям (для плашки в шапке).
|
||
$expense_ids = [];
|
||
foreach ($tree as $items) {
|
||
foreach ($items as $c) {
|
||
if ($c->type === 'expense') {
|
||
$expense_ids[(int)$c->id] = true;
|
||
}
|
||
}
|
||
}
|
||
$plan_expense = 0.0;
|
||
$fact_expense = 0.0;
|
||
foreach ($expense_ids as $categorie_id => $_) {
|
||
$plan_expense += $plan_month[$categorie_id] ?? 0.0;
|
||
$fact_expense += $fact_month[$categorie_id] ?? 0.0;
|
||
}
|
||
$pct_expense = $plan_expense > 0 ? round($fact_expense / $plan_expense * 100) : null;
|
||
|
||
$goals = $user ? (new GoalRepository())->getForUser($user->id) : [];
|
||
|
||
return $this->render('index', [
|
||
'user' => $auth_user,
|
||
'accounts' => $accounts ?: [],
|
||
'archived_accounts' => $archived_accounts ?: [],
|
||
'total' => $total,
|
||
'total_all' => $total_all,
|
||
'tree' => $tree,
|
||
'plan_month' => $plan_month,
|
||
'fact_month' => $fact_month,
|
||
'pct_expense' => $pct_expense,
|
||
'goals' => $goals ?: [],
|
||
'month' => $month,
|
||
]);
|
||
}
|
||
}
|