first commit
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
/**
|
||||
* Logowanie jednego uzytkownika wprost z .env (user_email + user_password).
|
||||
* ponytail: jawne haslo z .env, narzedzie jednoosobowe. Podniesc do password_hash,
|
||||
* jesli kiedys pojawi sie wielu uzytkownikow / tabela users.
|
||||
*/
|
||||
class Auth extends BaseController
|
||||
{
|
||||
public function login()
|
||||
{
|
||||
if (session()->get('logged_in')) {
|
||||
return redirect()->to('/dashboard');
|
||||
}
|
||||
|
||||
if (strtolower($this->request->getMethod()) === 'post') {
|
||||
$email = trim((string) $this->request->getPost('email'));
|
||||
$pass = (string) $this->request->getPost('password');
|
||||
|
||||
$okEmail = (string) env('user_email');
|
||||
$okPass = (string) env('user_password');
|
||||
|
||||
if ($okEmail !== '' && hash_equals($okEmail, $email) && hash_equals($okPass, $pass)) {
|
||||
session()->set([
|
||||
'logged_in' => true,
|
||||
'user_email' => $email,
|
||||
]);
|
||||
|
||||
return redirect()->to('/dashboard');
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', 'Nieprawidłowy email lub hasło.');
|
||||
}
|
||||
|
||||
return view('auth/login');
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
session()->destroy();
|
||||
|
||||
return redirect()->to('/login');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* BaseController provides a convenient place for loading components
|
||||
* and performing functions that are needed by all your controllers.
|
||||
*
|
||||
* Extend this class in any new controllers:
|
||||
* ```
|
||||
* class Home extends BaseController
|
||||
* ```
|
||||
*
|
||||
* For security, be sure to declare any new methods as protected or private.
|
||||
*/
|
||||
abstract class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* Be sure to declare properties for any property fetch you initialized.
|
||||
* The creation of dynamic property is deprecated in PHP 8.2.
|
||||
*/
|
||||
|
||||
// protected $session;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
||||
{
|
||||
// Load here all helpers you want to be available in your controllers that extend BaseController.
|
||||
// Caution: Do not put the this below the parent::initController() call below.
|
||||
$this->helpers = ['form', 'url'];
|
||||
|
||||
// Caution: Do not edit this line.
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
// Preload any models, libraries, etc, here.
|
||||
// $this->session = service('session');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\CategoryModel;
|
||||
|
||||
class Categories extends BaseController
|
||||
{
|
||||
private function model(): CategoryModel
|
||||
{
|
||||
return model(CategoryModel::class);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('categories/index', [
|
||||
'title' => 'Kategorie',
|
||||
'categories' => $this->model()->tree(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
return view('categories/form', [
|
||||
'title' => 'Nowa kategoria',
|
||||
'cat' => null,
|
||||
'parents' => $this->model()->tree(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return $this->persist(null);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$cat = $this->model()->find((int) $id);
|
||||
if (! $cat) {
|
||||
return redirect()->to('/categories')->with('error', 'Nie znaleziono kategorii.');
|
||||
}
|
||||
|
||||
return view('categories/form', [
|
||||
'title' => 'Edycja kategorii',
|
||||
'cat' => $cat,
|
||||
'parents' => $this->model()->tree(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
{
|
||||
return $this->persist((int) $id);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$id = (int) $id;
|
||||
if ($this->model()->usedByOperations($id)) {
|
||||
return redirect()->to('/categories')
|
||||
->with('error', 'Nie można usunąć kategorii używanej przez operacje. Najpierw przenieś lub usuń te operacje.');
|
||||
}
|
||||
$this->model()->delete($id);
|
||||
|
||||
return redirect()->to('/categories')->with('success', 'Kategoria usunięta.');
|
||||
}
|
||||
|
||||
private function persist(?int $id)
|
||||
{
|
||||
$data = [
|
||||
'name' => trim((string) $this->request->getPost('name')),
|
||||
'type' => (string) $this->request->getPost('type'),
|
||||
'parent_id' => $this->request->getPost('parent_id') ?: null,
|
||||
];
|
||||
|
||||
// Kategoria nie moze byc wlasnym rodzicem
|
||||
if ($id !== null && (int) $data['parent_id'] === $id) {
|
||||
$data['parent_id'] = null;
|
||||
}
|
||||
|
||||
$model = $this->model();
|
||||
if ($id !== null) {
|
||||
$ok = $model->update($id, $data);
|
||||
} else {
|
||||
$ok = $model->insert($data);
|
||||
}
|
||||
|
||||
if ($ok === false) {
|
||||
return redirect()->back()->withInput()
|
||||
->with('error', implode(' ', $model->errors()));
|
||||
}
|
||||
|
||||
return redirect()->to('/categories')->with('success', 'Zapisano kategorię.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\InstrumentModel;
|
||||
use App\Models\OperationModel;
|
||||
|
||||
class Dashboard extends BaseController
|
||||
{
|
||||
/**
|
||||
* Pulpit globalny — przegląd całości: finanse bieżące (rok) + inwestycje + majątek razem.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$from = date('Y-01-01');
|
||||
$to = date('Y-12-31');
|
||||
|
||||
$fin = model(OperationModel::class)->totals(['from' => $from, 'to' => $to]);
|
||||
|
||||
// Agregat inwestycji spójny ze źródłem prawdy w InstrumentModel::withStats.
|
||||
$net = 0.0;
|
||||
$val = 0.0;
|
||||
foreach (model(InstrumentModel::class)->withStats() as $i) {
|
||||
$net += (float) $i['net_invested'];
|
||||
$val += (float) $i['value'];
|
||||
}
|
||||
$inv = [
|
||||
'net_invested' => round($net, 2),
|
||||
'value' => round($val, 2),
|
||||
'profit' => round($val - $net, 2),
|
||||
];
|
||||
|
||||
return view('dashboard/index', [
|
||||
'title' => 'Pulpit',
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
'fin' => $fin,
|
||||
'inv' => $inv,
|
||||
'net_worth' => round($fin['balance'] + $val, 2),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulpit finansów bieżących — wykresy przychody/wydatki/saldo.
|
||||
*/
|
||||
public function finances()
|
||||
{
|
||||
$from = $this->request->getGet('from') ?: date('Y-01-01');
|
||||
$to = $this->request->getGet('to') ?: date('Y-12-31');
|
||||
|
||||
$model = model(OperationModel::class);
|
||||
|
||||
return view('dashboard/finances', [
|
||||
'title' => 'Pulpit finansów',
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
'totals' => $model->totals(['from' => $from, 'to' => $to]),
|
||||
'monthly' => $model->monthlyBalance($from, $to),
|
||||
'byCat' => $model->byCategory($from, $to, 'expense'),
|
||||
'running' => $model->runningBalance($from, $to),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class Home extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
return view('welcome_message');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\InstrumentModel;
|
||||
|
||||
class Instruments extends BaseController
|
||||
{
|
||||
private function model(): InstrumentModel
|
||||
{
|
||||
return model(InstrumentModel::class);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('instruments/index', [
|
||||
'title' => 'Instrumenty',
|
||||
'instruments' => $this->model()->withStats(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
return view('instruments/form', [
|
||||
'title' => 'Nowy instrument',
|
||||
'instrument' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return $this->persist(null);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$instrument = $this->model()->find((int) $id);
|
||||
if (! $instrument) {
|
||||
return redirect()->to('/instruments')->with('error', 'Nie znaleziono instrumentu.');
|
||||
}
|
||||
|
||||
return view('instruments/form', [
|
||||
'title' => 'Edycja instrumentu',
|
||||
'instrument' => $instrument,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
{
|
||||
return $this->persist((int) $id);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$id = (int) $id;
|
||||
if ($this->model()->hasChildren($id)) {
|
||||
return redirect()->to('/instruments')
|
||||
->with('error', 'Nie można usunąć instrumentu z operacjami lub wycenami. Najpierw usuń powiązane wpisy.');
|
||||
}
|
||||
$this->model()->delete($id);
|
||||
|
||||
return redirect()->to('/instruments')->with('success', 'Instrument usunięty.');
|
||||
}
|
||||
|
||||
private function persist(?int $id)
|
||||
{
|
||||
$data = ['name' => trim((string) $this->request->getPost('name'))];
|
||||
|
||||
$model = $this->model();
|
||||
$ok = $id !== null ? $model->update($id, $data) : $model->insert($data);
|
||||
|
||||
if ($ok === false) {
|
||||
return redirect()->back()->withInput()
|
||||
->with('error', implode(' ', $model->errors()));
|
||||
}
|
||||
|
||||
return redirect()->to('/instruments')->with('success', 'Zapisano instrument.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\InstrumentModel;
|
||||
use App\Models\InvOperationModel;
|
||||
|
||||
class InvOperations extends BaseController
|
||||
{
|
||||
private function model(): InvOperationModel
|
||||
{
|
||||
return model(InvOperationModel::class);
|
||||
}
|
||||
|
||||
private function instruments(): array
|
||||
{
|
||||
return model(InstrumentModel::class)->orderBy('name', 'ASC')->findAll();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$f = [
|
||||
'from' => $this->request->getGet('from'),
|
||||
'to' => $this->request->getGet('to'),
|
||||
'instrument_id' => $this->request->getGet('instrument_id'),
|
||||
'type' => $this->request->getGet('type'),
|
||||
];
|
||||
|
||||
return view('inv_operations/index', [
|
||||
'title' => 'Operacje inwestycyjne',
|
||||
'operations' => $this->model()->filtered($f),
|
||||
'instruments' => $this->instruments(),
|
||||
'filter' => $f,
|
||||
]);
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
return view('inv_operations/form', [
|
||||
'title' => 'Nowa operacja inwestycyjna',
|
||||
'op' => null,
|
||||
'instruments' => $this->instruments(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return $this->persist(null);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$op = $this->model()->find((int) $id);
|
||||
if (! $op) {
|
||||
return redirect()->to('/investments/operations')->with('error', 'Nie znaleziono operacji.');
|
||||
}
|
||||
|
||||
return view('inv_operations/form', [
|
||||
'title' => 'Edycja operacji inwestycyjnej',
|
||||
'op' => $op,
|
||||
'instruments' => $this->instruments(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
{
|
||||
return $this->persist((int) $id);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$this->model()->delete((int) $id);
|
||||
|
||||
return redirect()->to('/investments/operations')->with('success', 'Operacja usunięta.');
|
||||
}
|
||||
|
||||
private function persist(?int $id)
|
||||
{
|
||||
$type = (string) $this->request->getPost('type');
|
||||
$data = [
|
||||
'instrument_id' => (int) $this->request->getPost('instrument_id') ?: null,
|
||||
'date' => (string) $this->request->getPost('date'),
|
||||
'amount' => (string) $this->request->getPost('amount'),
|
||||
'type' => in_array($type, ['deposit', 'withdraw'], true) ? $type : 'deposit',
|
||||
'description' => trim((string) $this->request->getPost('description')) ?: null,
|
||||
];
|
||||
|
||||
$model = $this->model();
|
||||
$ok = $id !== null ? $model->update($id, $data) : $model->insert($data);
|
||||
|
||||
if ($ok === false) {
|
||||
return redirect()->back()->withInput()
|
||||
->with('error', implode(' ', $model->errors()));
|
||||
}
|
||||
|
||||
return redirect()->to('/investments/operations')->with('success', 'Zapisano operację.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\InstrumentModel;
|
||||
|
||||
class Investments extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$model = model(InstrumentModel::class);
|
||||
$instruments = $model->withStats();
|
||||
|
||||
// Kafelki portfela = suma po instrumentach (spojne ze zrodlem prawdy w withStats).
|
||||
$netInvested = 0.0;
|
||||
$value = 0.0;
|
||||
foreach ($instruments as $i) {
|
||||
$netInvested += (float) $i['net_invested'];
|
||||
$value += (float) $i['value'];
|
||||
}
|
||||
|
||||
return view('investments/index', [
|
||||
'title' => 'Pulpit inwestycji',
|
||||
'instruments' => $instruments,
|
||||
'net_invested' => round($netInvested, 2),
|
||||
'value' => round($value, 2),
|
||||
'profit' => round($value - $netInvested, 2),
|
||||
'timeline' => $model->portfolioTimeline(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\CategoryModel;
|
||||
use App\Models\OperationModel;
|
||||
|
||||
class Operations extends BaseController
|
||||
{
|
||||
private function model(): OperationModel
|
||||
{
|
||||
return model(OperationModel::class);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$f = [
|
||||
'from' => $this->request->getGet('from'),
|
||||
'to' => $this->request->getGet('to'),
|
||||
'category_id' => $this->request->getGet('category_id'),
|
||||
'type' => $this->request->getGet('type'),
|
||||
];
|
||||
|
||||
return view('operations/index', [
|
||||
'title' => 'Operacje',
|
||||
'operations' => $this->model()->filtered($f),
|
||||
'totals' => $this->model()->totals($f),
|
||||
'categories' => model(CategoryModel::class)->tree(),
|
||||
'filter' => $f,
|
||||
]);
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
return view('operations/form', [
|
||||
'title' => 'Nowa operacja',
|
||||
'op' => null,
|
||||
'categories' => model(CategoryModel::class)->tree(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return $this->persist(null);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$op = $this->model()->find((int) $id);
|
||||
if (! $op) {
|
||||
return redirect()->to('/operations')->with('error', 'Nie znaleziono operacji.');
|
||||
}
|
||||
|
||||
return view('operations/form', [
|
||||
'title' => 'Edycja operacji',
|
||||
'op' => $op,
|
||||
'categories' => model(CategoryModel::class)->tree(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
{
|
||||
return $this->persist((int) $id);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$this->model()->delete((int) $id);
|
||||
|
||||
return redirect()->to('/operations')->with('success', 'Operacja usunięta.');
|
||||
}
|
||||
|
||||
private function persist(?int $id)
|
||||
{
|
||||
$categoryId = $this->request->getPost('category_id') ?: null;
|
||||
$type = (string) $this->request->getPost('type');
|
||||
|
||||
// Zrodlo prawdy dla typu: wybrana kategoria narzuca typ operacji.
|
||||
if ($categoryId !== null) {
|
||||
$cat = model(CategoryModel::class)->find((int) $categoryId);
|
||||
if ($cat) {
|
||||
$type = $cat['type'];
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'date' => (string) $this->request->getPost('date'),
|
||||
'amount' => (string) $this->request->getPost('amount'),
|
||||
'type' => $type,
|
||||
'category_id' => $categoryId,
|
||||
'description' => trim((string) $this->request->getPost('description')) ?: null,
|
||||
];
|
||||
|
||||
$model = $this->model();
|
||||
$ok = $id !== null ? $model->update($id, $data) : $model->insert($data);
|
||||
|
||||
if ($ok === false) {
|
||||
return redirect()->back()->withInput()
|
||||
->with('error', implode(' ', $model->errors()));
|
||||
}
|
||||
|
||||
return redirect()->to('/operations')->with('success', 'Zapisano operację.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\InstrumentModel;
|
||||
use App\Models\ValuationModel;
|
||||
|
||||
class Valuations extends BaseController
|
||||
{
|
||||
private function model(): ValuationModel
|
||||
{
|
||||
return model(ValuationModel::class);
|
||||
}
|
||||
|
||||
private function instruments(): array
|
||||
{
|
||||
return model(InstrumentModel::class)->orderBy('name', 'ASC')->findAll();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$f = ['instrument_id' => $this->request->getGet('instrument_id')];
|
||||
|
||||
return view('valuations/index', [
|
||||
'title' => 'Wyceny',
|
||||
'valuations' => $this->model()->filtered($f),
|
||||
'instruments' => $this->instruments(),
|
||||
'filter' => $f,
|
||||
]);
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
return view('valuations/form', [
|
||||
'title' => 'Nowa wycena',
|
||||
'val' => null,
|
||||
'instruments' => $this->instruments(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return $this->persist(null);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$val = $this->model()->find((int) $id);
|
||||
if (! $val) {
|
||||
return redirect()->to('/investments/valuations')->with('error', 'Nie znaleziono wyceny.');
|
||||
}
|
||||
|
||||
return view('valuations/form', [
|
||||
'title' => 'Edycja wyceny',
|
||||
'val' => $val,
|
||||
'instruments' => $this->instruments(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
{
|
||||
return $this->persist((int) $id);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$this->model()->delete((int) $id);
|
||||
|
||||
return redirect()->to('/investments/valuations')->with('success', 'Wycena usunięta.');
|
||||
}
|
||||
|
||||
private function persist(?int $id)
|
||||
{
|
||||
$data = [
|
||||
'instrument_id' => (int) $this->request->getPost('instrument_id') ?: null,
|
||||
'date' => (string) $this->request->getPost('date'),
|
||||
'value' => (string) $this->request->getPost('value'),
|
||||
];
|
||||
|
||||
$model = $this->model();
|
||||
$ok = $id !== null ? $model->update($id, $data) : $model->insert($data);
|
||||
|
||||
if ($ok === false) {
|
||||
return redirect()->back()->withInput()
|
||||
->with('error', implode(' ', $model->errors()));
|
||||
}
|
||||
|
||||
return redirect()->to('/investments/valuations')->with('success', 'Zapisano wycenę.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user