сумма] — факт за текущий месяц (реальные transactions)
* @var int|null $pct_expense % бюджета по расходам за месяц (факт/план), null — если план не задан
* @var object[] $goals Цели пользователя + данные счёта-копилки (account_title/account_summa/account_currency)
*/
use App\Classes\Currency;
use System\Classes\CSRF;
$type_icons = [
'cash' => 'ic-wallet',
'bank' => 'ic-card',
'savings' => 'ic-piggy',
];
$type_accents = [
'cash' => 'var(--teal)',
'bank' => 'var(--blue)',
'savings' => 'var(--purple)',
];
$type_labels = [
'cash' => 'Наличные',
'bank' => 'Банковский счёт',
'savings' => 'Копилка',
];
$weekdays = [1 => 'Понедельник', 2 => 'Вторник', 3 => 'Среда', 4 => 'Четверг', 5 => 'Пятница', 6 => 'Суббота', 7 => 'Воскресенье'];
$month_names = [
1 => 'январь', 2 => 'февраль', 3 => 'март', 4 => 'апрель', 5 => 'май', 6 => 'июнь',
7 => 'июль', 8 => 'август', 9 => 'сентябрь', 10 => 'октябрь', 11 => 'ноябрь', 12 => 'декабрь',
];
$month_names_gen = [
1 => 'января', 2 => 'февраля', 3 => 'марта', 4 => 'апреля', 5 => 'мая', 6 => 'июня',
7 => 'июля', 8 => 'августа', 9 => 'сентября', 10 => 'октября', 11 => 'ноября', 12 => 'декабря',
];
$ucfirstMb = static fn (string $s): string => mb_strtoupper(mb_substr($s, 0, 1)) . mb_substr($s, 1);
$this->setScript('accounts.js');
?>
= $weekdays[(int)date('N')] ?>, = (int)date('j') ?> = $month_names_gen[(int)date('n')] ?>
📅 = $ucfirstMb($month_names[(int)date('n')]) ?> = date('Y') ?>
100; ?>
Бюджет = $pct_expense ?>% потрачено
Здравствуйте, = htmlspecialchars($user['full_name'] ?? $user['login'], ENT_QUOTES, 'UTF-8') ?>
Доступно сейчас
= number_format($total, 0, ',', ' ') ?> ₽
Всего по всем счетам = number_format($total_all, 0, ',', ' ') ?> ₽
Пока нет ни одного счёта — нажмите «+», чтобы добавить первый
= htmlspecialchars($account->title, ENT_QUOTES, 'UTF-8') ?>
= $type_labels[$account->type_acc] ?? '' ?>
= number_format((float)$account->summa, 2, ',', ' ') ?>
= htmlspecialchars($account->currency, ENT_QUOTES, 'UTF-8') ?>
Копилки и цели
account_summa;
$target = (float)$goal->target_summa;
$pct = $target > 0 ? min(100, $saved / $target * 100) : 0;
$r = 22;
$circumference = 2 * M_PI * $r;
$offset = $circumference * (1 - $pct / 100);
?>
= round($pct) ?>%
= htmlspecialchars($goal->account_title, ENT_QUOTES, 'UTF-8') ?>
= number_format($saved, 0, ',', ' ') ?> из = number_format($target, 0, ',', ' ') ?>
= htmlspecialchars($goal->account_currency, ENT_QUOTES, 'UTF-8') ?>
$g->type === $type);
if ($type_groups === []) {
echo 'Нет статей — добавьте их на странице «Статьи»
';
return;
}
// Строка одной статьи (или самостоятельной группы без детей) — план+факт+прогресс-бар.
// Перерасход (факт > плана) для расходов подсвечивается красным — для доходов это, наоборот,
// хорошо (получено больше плана), там всегда акцентный цвет.
$renderRow = static function (object $category, float $plan, float $fact, string $type): void {
$pct = $plan > 0 ? round($fact / $plan * 100) : ($fact > 0 ? 100 : 0);
$bar_width = min(100, $pct);
$over = $type === 'expense' && $fact > $plan && $plan > 0;
$pct_color = $over ? 'var(--red)' : 'var(--accent-tint)';
$bar_color = $over ? 'var(--red)' : 'var(--accent)';
echo ''
. '
'
. '
' . htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') . '
'
. '
'
. '
' . number_format($fact, 0, ',', ' ') . ' из ' . number_format($plan, 0, ',', ' ') . ' ₽
'
. '
'
. '
' . $pct . '%
'
. '
';
};
echo '';
foreach ($type_groups as $group) {
$children = $tree[$group->id] ?? [];
// Заголовок-плашка — ВСЕГДА, и у настоящей группы, и у самостоятельной статьи (тогда
// плашка — единственная строка на неё, показывает сразу и название, и сумму). Без этого
// самостоятельная статья визуально не отличалась от рядового члена предыдущей группы
// (см. фидбек пользователя — тонкой разницы фона недостаточно, нужна однозначная граница).
$head_plan = $children !== []
? array_sum(array_map(static fn ($c) => $plan_month[$c->id] ?? 0.0, $children))
: ($plan_month[$group->id] ?? 0.0);
echo '
'
. '' . htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') . ' '
. '' . number_format($head_plan, 0, ',', ' ') . ' ₽ '
. '
';
// Самостоятельная статья (без подкатегорий) — плашка выше уже единственная строка на неё
// (название+план), отдельного .budget-row для неё не рисуем (см. комментарий выше).
foreach ($children as $category) {
$renderRow($category, $plan_month[$category->id] ?? 0.0, $fact_month[$category->id] ?? 0.0, $type);
}
}
echo '
';
};
?>
Доходы
Бюджет на = $month_names[$month] ?? '' ?>
Архив пуст
= htmlspecialchars($account->title, ENT_QUOTES, 'UTF-8') ?>
= number_format((float)$account->summa, 2, ',', ' ') ?>
= htmlspecialchars($account->currency, ENT_QUOTES, 'UTF-8') ?>
Восстановить