first commit
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class OperationModel extends Model
|
||||
{
|
||||
protected $table = 'operations';
|
||||
protected $primaryKey = 'id';
|
||||
protected $returnType = 'array';
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['date', 'amount', 'type', 'category_id', 'description'];
|
||||
|
||||
protected $validationRules = [
|
||||
'date' => 'required|valid_date[Y-m-d]',
|
||||
'amount' => 'required|decimal|greater_than[0]',
|
||||
'type' => 'required|in_list[income,expense]',
|
||||
'category_id' => 'permit_empty|is_natural_no_zero',
|
||||
'description' => 'permit_empty|max_length[255]',
|
||||
];
|
||||
|
||||
/**
|
||||
* Lista operacji z nazwa kategorii, z filtrami.
|
||||
* $f: from, to, category_id, type (wszystkie opcjonalne).
|
||||
*/
|
||||
public function filtered(array $f): array
|
||||
{
|
||||
$b = $this->db->table('operations o')
|
||||
->select('o.*, c.name AS category_name, p.name AS parent_name')
|
||||
->join('categories c', 'c.id = o.category_id', 'left')
|
||||
->join('categories p', 'p.id = c.parent_id', 'left');
|
||||
|
||||
if (! empty($f['from'])) {
|
||||
$b->where('o.date >=', $f['from']);
|
||||
}
|
||||
if (! empty($f['to'])) {
|
||||
$b->where('o.date <=', $f['to']);
|
||||
}
|
||||
if (! empty($f['category_id'])) {
|
||||
$b->where('o.category_id', (int) $f['category_id']);
|
||||
}
|
||||
if (! empty($f['type'])) {
|
||||
$b->where('o.type', $f['type']);
|
||||
}
|
||||
|
||||
return $b->orderBy('o.date', 'DESC')->orderBy('o.id', 'DESC')->get()->getResultArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sumy przychodow/wydatkow/salda dla zakresu (i opcjonalnych filtrow).
|
||||
*/
|
||||
public function totals(array $f): array
|
||||
{
|
||||
$b = $this->db->table('operations o')
|
||||
->select("SUM(CASE WHEN o.type='income' THEN o.amount ELSE 0 END) AS income")
|
||||
->select("SUM(CASE WHEN o.type='expense' THEN o.amount ELSE 0 END) AS expense");
|
||||
|
||||
if (! empty($f['from'])) {
|
||||
$b->where('o.date >=', $f['from']);
|
||||
}
|
||||
if (! empty($f['to'])) {
|
||||
$b->where('o.date <=', $f['to']);
|
||||
}
|
||||
if (! empty($f['category_id'])) {
|
||||
$b->where('o.category_id', (int) $f['category_id']);
|
||||
}
|
||||
if (! empty($f['type'])) {
|
||||
$b->where('o.type', $f['type']);
|
||||
}
|
||||
|
||||
$row = $b->get()->getRowArray() ?: [];
|
||||
$income = (float) ($row['income'] ?? 0);
|
||||
$expense = (float) ($row['expense'] ?? 0);
|
||||
|
||||
return [
|
||||
'income' => $income,
|
||||
'expense' => $expense,
|
||||
'balance' => $income - $expense,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bilans miesieczny: [ ['ym'=>'2026-07','income'=>..,'expense'=>..], ... ].
|
||||
*/
|
||||
public function monthlyBalance(string $from, string $to): array
|
||||
{
|
||||
return $this->db->table('operations')
|
||||
->select("DATE_FORMAT(date, '%Y-%m') AS ym")
|
||||
->select("SUM(CASE WHEN type='income' THEN amount ELSE 0 END) AS income")
|
||||
->select("SUM(CASE WHEN type='expense' THEN amount ELSE 0 END) AS expense")
|
||||
->where('date >=', $from)->where('date <=', $to)
|
||||
->groupBy('ym')->orderBy('ym', 'ASC')
|
||||
->get()->getResultArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suma wg kategorii dla danego typu: [ ['name'=>..,'total'=>..], ... ].
|
||||
*/
|
||||
public function byCategory(string $from, string $to, string $type): array
|
||||
{
|
||||
$rows = $this->db->table('operations o')
|
||||
->select('o.category_id, c.name AS cat_name, p.name AS parent_name, SUM(o.amount) AS total')
|
||||
->join('categories c', 'c.id = o.category_id', 'left')
|
||||
->join('categories p', 'p.id = c.parent_id', 'left')
|
||||
->where('o.type', $type)
|
||||
->where('o.date >=', $from)->where('o.date <=', $to)
|
||||
->groupBy('o.category_id')->groupBy('c.name')->groupBy('p.name')
|
||||
->orderBy('total', 'DESC')
|
||||
->get()->getResultArray();
|
||||
|
||||
// Etykieta = pelna sciezka kategoria -> podkategoria
|
||||
foreach ($rows as &$r) {
|
||||
if (empty($r['cat_name'])) {
|
||||
$r['name'] = '(bez kategorii)';
|
||||
} elseif (! empty($r['parent_name'])) {
|
||||
$r['name'] = $r['parent_name'] . ' → ' . $r['cat_name'];
|
||||
} else {
|
||||
$r['name'] = $r['cat_name'];
|
||||
}
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saldo skumulowane w czasie: [ ['date'=>..,'balance'=>..], ... ].
|
||||
*/
|
||||
public function runningBalance(string $from, string $to): array
|
||||
{
|
||||
$rows = $this->db->table('operations')
|
||||
->select('date')
|
||||
->select("SUM(CASE WHEN type='income' THEN amount ELSE -amount END) AS net")
|
||||
->where('date >=', $from)->where('date <=', $to)
|
||||
->groupBy('date')->orderBy('date', 'ASC')
|
||||
->get()->getResultArray();
|
||||
|
||||
$balance = 0.0;
|
||||
$out = [];
|
||||
foreach ($rows as $r) {
|
||||
$balance += (float) $r['net'];
|
||||
$out[] = ['date' => $r['date'], 'balance' => round($balance, 2)];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user