Skip to content

Rejestr wydatków miesięcznych

This content is not available in your language yet.

Stworzysz Rejestr wydatków miesięcznych - aplikację do śledzenia i kategoryzowania wydatków. System pozwala na przeglądanie wydatków w wybranym miesiącu, generowanie raportów według kategorii i analizę struktury kosztów.

Czego się nauczysz?

  • Walidacji danych liczbowych (kwoty)
  • Pracy z datami i filtrowania po miesiącach
  • Kategoryzacji danych (enum kategorii)
  • Obliczania sum i procentów
  • Tworzenia raportów finansowych

W prawdziwej pracy...

Rejestry wydatków są podstawą aplikacji finansowych - od osobistych budżetów (Mint, YNAB) po systemy księgowe firm. Umiejętność projektowania systemów z ewidencją transakcji, kategoriami i raportami jest fundamentem dla każdego programisty aplikacji finansowych i e-commerce.

  1. Formularz dodawania wydatku Użytkownik podaje kwotę, wybiera kategorię z listy, opcjonalnie podaje datę i opis wydatku.

  2. Walidacja danych System sprawdza poprawność wprowadzonych danych - czy kwota jest dodatnia, czy kategoria jest z dozwolonej listy.

  3. Lista wydatków Wszystkie wydatki są wyświetlane w formie listy z podsumowaniem sumy.

  4. Podsumowanie miesięczne System oblicza sumę wydatków w bieżącym miesiącu i może pokazywać różne miesiące.

Przykładowa struktura pliku JSON:

{
"expenses": [
{
"id": 1,
"amount": 45.50,
"category": "jedzenie",
"date": "2026-02-10",
"description": "Zakupy w Biedronce",
"created_at": "2026-02-10 18:30:00"
},
{
"id": 2,
"amount": 150.00,
"category": "transport",
"date": "2026-02-11",
"description": "Bilet miesięczny",
"created_at": "2026-02-11 08:00:00"
},
{
"id": 3,
"amount": 89.99,
"category": "rozrywka",
"date": "2026-02-12",
"description": "Netflix + Spotify",
"created_at": "2026-02-12 20:00:00"
},
{
"id": 4,
"amount": 250.00,
"category": "rachunki",
"date": "2026-02-15",
"description": "Prąd",
"created_at": "2026-02-15 10:30:00"
}
]
}
KategoriaIkonaKolor
jedzenie🍕#e74c3c
transport🚌#3498db
rozrywka🎬#9b59b6
rachunki💡#f39c12
zakupy🛒#2ecc71
zdrowie💊#1abc9c
inne📦#95a5a6

Wymagane funkcje:

  • Formularz z polami: kwota, kategoria (select), opis
  • Walidacja danych w PHP (kwota > 0, kategoria z listy)
  • Lista wszystkich wydatków
  • Suma wydatków
  • Prosty interfejs CSS

Przykładowy scenariusz:

Użytkownik wpisuje kwotę 45.50 zł, wybiera kategorię “jedzenie”, dodaje opis “Zakupy”. Po zapisie widzi wydatek na liście. Na dole: “Suma: 535,49 zł”.

Ocena: 3.0

Walidacja danych wejściowych:

$amount = filter_var($_POST['amount'] ?? '', FILTER_VALIDATE_FLOAT);
$category = $_POST['category'] ?? '';
$date = $_POST['date'] ?? date('Y-m-d');
if ($amount === false || $amount <= 0) {
$errors[] = "Kwota musi być liczbą dodatnią";
}
if ($amount > 100000) {
$errors[] = "Kwota wydaje się zbyt duża";
}
$validCategories = ['jedzenie', 'transport', 'rozrywka', 'rachunki', 'zakupy', 'zdrowie', 'inne'];
if (!in_array($category, $validCategories)) {
$errors[] = "Wybierz poprawną kategorię";
}
// Walidacja daty (nie z przyszłości)
if ($date > date('Y-m-d')) {
$errors[] = "Data nie może być z przyszłości";
}

Kategorie z kolorami i ikonami:

function getCategories(): array {
return [
'jedzenie' => ['label' => 'Jedzenie', 'icon' => '🍕', 'color' => '#e74c3c'],
'transport' => ['label' => 'Transport', 'icon' => '🚌', 'color' => '#3498db'],
'rozrywka' => ['label' => 'Rozrywka', 'icon' => '🎬', 'color' => '#9b59b6'],
'rachunki' => ['label' => 'Rachunki', 'icon' => '💡', 'color' => '#f39c12'],
'zakupy' => ['label' => 'Zakupy', 'icon' => '🛒', 'color' => '#2ecc71'],
'zdrowie' => ['label' => 'Zdrowie', 'icon' => '💊', 'color' => '#1abc9c'],
'inne' => ['label' => 'Inne', 'icon' => '📦', 'color' => '#95a5a6'],
];
}
function getCategoryInfo(string $category): array {
$categories = getCategories();
return $categories[$category] ?? $categories['inne'];
}

Filtrowanie po miesiącu:

function filterByMonth(array $expenses, int $year, int $month): array {
return array_filter($expenses, function($expense) use ($year, $month) {
$expenseDate = strtotime($expense['date']);
return date('Y', $expenseDate) == $year && date('n', $expenseDate) == $month;
});
}
function getAvailableMonths(array $expenses): array {
$months = [];
foreach ($expenses as $expense) {
$yearMonth = date('Y-m', strtotime($expense['date']));
if (!in_array($yearMonth, $months)) {
$months[] = $yearMonth;
}
}
rsort($months); // Najnowsze pierwsze
return $months;
}
function formatMonth(string $yearMonth): string {
$monthNames = [
'01' => 'Styczeń', '02' => 'Luty', '03' => 'Marzec',
'04' => 'Kwiecień', '05' => 'Maj', '06' => 'Czerwiec',
'07' => 'Lipiec', '08' => 'Sierpień', '09' => 'Wrzesień',
'10' => 'Październik', '11' => 'Listopad', '12' => 'Grudzień',
];
list($year, $month) = explode('-', $yearMonth);
return $monthNames[$month] . ' ' . $year;
}

Raport według kategorii:

function getCategoryReport(array $expenses): array {
$report = [];
$total = 0;
foreach ($expenses as $expense) {
$category = $expense['category'];
$amount = $expense['amount'];
if (!isset($report[$category])) {
$report[$category] = ['amount' => 0, 'count' => 0];
}
$report[$category]['amount'] += $amount;
$report[$category]['count']++;
$total += $amount;
}
// Dodaj procenty
foreach ($report as $category => &$data) {
$data['percentage'] = $total > 0
? round(($data['amount'] / $total) * 100, 1)
: 0;
}
// Sortuj po kwocie malejąco
uasort($report, fn($a, $b) => $b['amount'] <=> $a['amount']);
return [
'categories' => $report,
'total' => round($total, 2),
];
}

Porównanie miesięcy:

function compareMonths(array $expenses, int $year, int $month): array {
$currentMonth = filterByMonth($expenses, $year, $month);
$currentTotal = array_sum(array_column($currentMonth, 'amount'));
// Poprzedni miesiąc
$prevMonth = $month - 1;
$prevYear = $year;
if ($prevMonth < 1) {
$prevMonth = 12;
$prevYear--;
}
$previousMonth = filterByMonth($expenses, $prevYear, $prevMonth);
$previousTotal = array_sum(array_column($previousMonth, 'amount'));
$difference = $currentTotal - $previousTotal;
$percentChange = $previousTotal > 0
? round(($difference / $previousTotal) * 100, 1)
: 0;
return [
'current' => round($currentTotal, 2),
'previous' => round($previousTotal, 2),
'difference' => round($difference, 2),
'percentage' => $percentChange,
'trend' => $difference > 0 ? 'up' : ($difference < 0 ? 'down' : 'stable'),
];
}

Sprawdzanie budżetu (wariant C):

function checkBudget(array $expenses, float $budgetLimit, int $year, int $month): array {
$monthExpenses = filterByMonth($expenses, $year, $month);
$spent = array_sum(array_column($monthExpenses, 'amount'));
$remaining = $budgetLimit - $spent;
$percentage = ($budgetLimit > 0) ? round(($spent / $budgetLimit) * 100, 1) : 0;
$status = 'ok';
$message = '';
if ($percentage >= 100) {
$status = 'exceeded';
$message = 'Przekroczono budżet o ' . abs(round($remaining, 2)) . '';
} elseif ($percentage >= 80) {
$status = 'warning';
$message = 'Wykorzystano ' . $percentage . '% budżetu';
}
return [
'budget' => $budgetLimit,
'spent' => round($spent, 2),
'remaining' => round($remaining, 2),
'percentage' => $percentage,
'status' => $status,
'message' => $message,
];
}

Formatowanie kwot:

function formatAmount(float $amount): string {
return number_format($amount, 2, ',', ' ') . '';
}

Wykorzystaj lekcje!

Cotygodniowe spotkania podczas lekcji to idealny moment, by:

  • Pokazać postępy - nawet małe kroki się liczą
  • Wyjaśnić wątpliwości - pytaj, nie zgaduj
  • Skonsultować rozwiązania - feedback pomoże Ci się rozwijać

Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!