Bicycle/App/Controller/IndexController.php
2026-08-15 19:40:29 +03:00

147 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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\CategoryGroupRepository;
use App\Repositories\CategoryRepository;
use App\Repositories\GoalRepository;
use App\Repositories\TransactionRepository;
use App\Repositories\UserRepository;
use Services\Auth;
use Services\CurrencyRate;
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') : [];
// Курс ЦБ РФ на не-RUB счета — Services\CurrencyRate; при недоступности источника rate()
// возвращает null для конкретного кода, тогда счёт просто не участвует в переводе в рубли
// (не показываем непересчитанную сумму как есть — это исказило бы «Доступно сейчас»).
$rate_service = CurrencyRate::instance();
$rates = [];
foreach ($accounts ?: [] as $account) {
if ($account->currency !== 'RUB' && !array_key_exists($account->currency, $rates)) {
$rates[$account->currency] = $rate_service->rate($account->currency);
}
}
$rubValue = static function (object $account) use ($rates): float {
if ($account->currency === 'RUB') {
return (float)$account->summa;
}
$rate = $rates[$account->currency] ?? null;
return $rate !== null ? (float)$account->summa * $rate : 0.0;
};
$total = array_sum(array_map(
static fn ($account) => $account->include_in_total ? $rubValue($account) : 0,
$accounts ?: []
));
// «Всего по всем счетам» — без фильтра include_in_total, для строки под «Доступно сейчас»
// (см. дизайн-хендофф App/design_handoff_personal_finance).
$total_all = array_sum(array_map($rubValue, $accounts ?: []));
$month = (int)date('n');
$year = (int)date('Y');
$category_repo = new CategoryRepository();
$budget_repo = new BudgetRepository();
$tree = $user ? $category_repo->getTree($user->id) : [];
$groups = $user ? (new CategoryGroupRepository())->getForUser($user->id) : [];
$plan_month = $user ? array_map(
static fn ($months) => $months[$month]['plan_summ'] ?? 0.0,
$budget_repo->getYear($user->id, $year)
) : [];
// Факт за месяц — реальные transactions (ручной ввод — App\Controller\TransactionsController).
$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;
$fact_income = 0.0;
foreach ($tree as $items) {
foreach ($items as $c) {
if ($c->type === 'income') {
$fact_income += $fact_month[(int)$c->id] ?? 0.0;
}
}
}
$month_delta = $fact_income - $fact_expense;
$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,
'groups' => $groups,
'plan_month' => $plan_month,
'fact_month' => $fact_month,
'pct_expense' => $pct_expense,
'month_delta' => $month_delta,
'goals' => $goals ?: [],
'month' => $month,
'rates' => $rates,
]);
}
public function testAction(): string
{
return str_replace(
['href="nocturne.css"', 'src="./support.js"'],
['href="/App/design_handoff_personal_finance/nocturne.css"', ''],
file_get_contents(APPPATH . '/design_handoff_personal_finance/Личные финансы.dc.html')
);
}
}