diff --git a/expenses_manager/expenses/forms.py b/expenses_manager/expenses/forms.py index fca301c..e94381a 100644 --- a/expenses_manager/expenses/forms.py +++ b/expenses_manager/expenses/forms.py @@ -1,5 +1,5 @@ from django import forms -from .models import Expense, Category, Tag, Account +from .models import Expense, Category, Income, Tag, Account class ExpenseForm(forms.ModelForm): @@ -38,4 +38,18 @@ class AccountForm(forms.ModelForm): class Meta: model = Account - fields = ['name', 'initial_balance', 'active'] \ No newline at end of file + fields = ['name', 'initial_balance', 'active'] + + +class IncomeForm(forms.ModelForm): + class Meta: + model = Income + fields = ['account', 'name', 'amount', 'date'] + + def __init__(self, *args, **kwargs): + user = kwargs.pop('user') + super().__init__(*args, **kwargs) + self.fields['account'].queryset = Account.objects.filter( + owner=user, + active=True, + ) \ No newline at end of file diff --git a/expenses_manager/expenses/migrations/0004_income.py b/expenses_manager/expenses/migrations/0004_income.py new file mode 100644 index 0000000..f9fc7c9 --- /dev/null +++ b/expenses_manager/expenses/migrations/0004_income.py @@ -0,0 +1,31 @@ +# Generated by Django 5.2.10 on 2026-02-01 18:27 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('expenses', '0003_alter_account_owner_alter_category_owner'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Income', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=150)), + ('amount', models.DecimalField(decimal_places=2, max_digits=12)), + ('date', models.DateField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incomes', to='expenses.account')), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-date'], + }, + ), + ] diff --git a/expenses_manager/expenses/models.py b/expenses_manager/expenses/models.py index d36b273..3449ffa 100644 --- a/expenses_manager/expenses/models.py +++ b/expenses_manager/expenses/models.py @@ -52,7 +52,11 @@ class Account(models.Model): self.expenses.aggregate(total=Sum('amount'))['total'] or Decimal('0') ) - return self.initial_balance - expenses_total + income_total = ( + self.incomes.aggregate(total=Sum('income'))['total'] + or Decimal('0') + ) + return self.initial_balance + income_total - expenses_total def __str__(self): return self.name @@ -108,4 +112,29 @@ class Expense(models.Model): ordering = ["-date"] def __str__(self): - return "{} - {}".format(self.date, self.amount) \ No newline at end of file + return "{} - {}".format(self.date, self.amount) + + +class Income(models.Model): + owner = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE + ) + account = models.ForeignKey( + Account, + on_delete=models.CASCADE, + related_name='incomes' + ) + + name = models.CharField(max_length=150) + amount = models.DecimalField(max_digits=12, decimal_places=2) + date = models.DateField() + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + ordering = ['-date'] + + def __str__(self): + return f'{self.name} - {self.amount}' + + \ No newline at end of file diff --git a/expenses_manager/expenses/views.py b/expenses_manager/expenses/views.py index 13730f5..aef8d4a 100644 --- a/expenses_manager/expenses/views.py +++ b/expenses_manager/expenses/views.py @@ -1,6 +1,6 @@ from datetime import date from operator import truediv -from .forms import ExpenseForm, TagForm +from .forms import ExpenseForm, IncomeForm, TagForm from .models import Account, Category, Expense, Tag # from dateutli.relativedelta import relativedelta @@ -610,5 +610,23 @@ def account_create(request): ) +@login_required +def income_create(request): + if request.method == 'POST': + form = IncomeForm(request.POST, user=request.user) + if form.is_valid(): + income = form.save(commit=False) + income.owner = request.user + income.save() + return redirect('home') + else: + form = IncomeForm(user=request.user) + + return render( + request, + 'expenses/income_form.html', + {'form': form} + ) +