Bicycle/App/Repositories/BudgetRepository.php
Egor Isaev c9b81cdcd1 dev
2026-08-14 13:09:54 +03:00

94 lines
3.4 KiB
PHP

<?php
/**
* @package Bicycle
* @author Egor Isaev
* @description BudgetRepository.php
* @copyright (c) 11/08/2026
*/
namespace App\Repositories;
use PDO;
use System\Classes\Repository;
/**
* Репозиторий таблицы budgets (план по категории на месяц; факт считается на лету из transactions).
*/
class BudgetRepository extends Repository
{
/**
* @var string Таблица categories для JOIN в getYear() — вынесена в свойство (не хардкод в SQL),
* чтобы тесты могли подменить её на временную, не трогая боевую таблицу categories.
*/
protected string $categories_table = 'categories';
/**
* @param string|null $connection Имя подключения (Database::instance($connection)); null — по умолчанию
*/
public function __construct(?string $connection = null)
{
parent::__construct('budgets', connection: $connection);
}
/**
* План на год пользователя, сгруппированный по статье и месяцу — для сетки на странице плана.
*
* @param int $user_id
* @param int $year
* @return array<int,array<int,array{plan_summ:float,formula_pct_used:?float}>>
*/
public function getYear(int $user_id, int $year): array
{
$sql = "SELECT b.categorie_id, b.month, b.plan_summ, b.formula_pct_used
FROM $this->table b
INNER JOIN $this->categories_table c ON c.id = b.categorie_id
WHERE c.user_id = :user_id AND b.year = :year";
$stmt = $this->pdo->prepare($sql);
$stmt->execute(['user_id' => $user_id, 'year' => $year]);
$result = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$result[(int)$row['categorie_id']][(int)$row['month']] = [
'plan_summ' => (float)$row['plan_summ'],
'formula_pct_used' => $row['formula_pct_used'] !== null ? (float)$row['formula_pct_used'] : null,
];
}
return $result;
}
/**
* Создать или обновить план статьи на конкретный месяц (по UNIQUE categorie_id+year+month).
*
* @param int $categorie_id
* @param int $year
* @param int $month
* @param float $plan_summ
* @param string $type income|expense
* @param float|null $formula_pct_used Только для строк, посчитанных по формуле связанной статьи
* @return void
*/
public function upsert(int $categorie_id, int $year, int $month, float $plan_summ, string $type, ?float $formula_pct_used = null): void
{
$existing = $this->getItemWhere("categorie_id = $categorie_id AND year = $year AND month = $month");
$data = [
'categorie_id' => $categorie_id,
'plan_summ' => $plan_summ,
'year' => $year,
'month' => $month,
'type' => $type,
'formula_pct_used' => $formula_pct_used,
];
if ($existing) {
$data['id'] = $existing->id;
$this->update($data);
} else {
$this->create($data);
}
}
}