diff options
Diffstat (limited to 'app/budget')
-rw-r--r-- | app/budget/migrations/0002_alter_luxpurchase_amount.py | 18 | ||||
-rw-r--r-- | app/budget/migrations/0003_alter_luxpurchase_category_alter_luxpurchase_source.py | 23 | ||||
-rw-r--r-- | app/budget/migrations/0004_alter_luxpurchase_source.py | 19 | ||||
-rw-r--r-- | app/budget/models.py | 36 | ||||
-rw-r--r-- | app/budget/templates/budget/base.html | 2 | ||||
-rw-r--r-- | app/budget/templates/budget/luxpurchase_list.html | 46 | ||||
-rw-r--r-- | app/budget/templates/budget/update_form.html | 20 | ||||
-rw-r--r-- | app/budget/urls.py | 2 | ||||
-rw-r--r-- | app/budget/views.py | 34 |
9 files changed, 194 insertions, 6 deletions
diff --git a/app/budget/migrations/0002_alter_luxpurchase_amount.py b/app/budget/migrations/0002_alter_luxpurchase_amount.py new file mode 100644 index 0000000..06400dd --- /dev/null +++ b/app/budget/migrations/0002_alter_luxpurchase_amount.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.6 on 2022-11-11 18:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('budget', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='luxpurchase', + name='amount', + field=models.DecimalField(decimal_places=2, max_digits=6), + ), + ] diff --git a/app/budget/migrations/0003_alter_luxpurchase_category_alter_luxpurchase_source.py b/app/budget/migrations/0003_alter_luxpurchase_category_alter_luxpurchase_source.py new file mode 100644 index 0000000..a880acf --- /dev/null +++ b/app/budget/migrations/0003_alter_luxpurchase_category_alter_luxpurchase_source.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-11-12 10:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('budget', '0002_alter_luxpurchase_amount'), + ] + + operations = [ + migrations.AlterField( + model_name='luxpurchase', + name='category', + field=models.IntegerField(choices=[(0, 'Grocery & Home'), (1, 'Gas'), (2, 'Bus'), (3, 'Lodging'), (4, 'Books'), (5, 'Clothes'), (6, 'Eating Out'), (7, 'Misc')], default=0), + ), + migrations.AlterField( + model_name='luxpurchase', + name='source', + field=models.IntegerField(choices=[(0, 'Walmart'), (1, 'Grocery Store'), (2, 'Gas Station'), (3, 'Amazon')], default=0), + ), + ] diff --git a/app/budget/migrations/0004_alter_luxpurchase_source.py b/app/budget/migrations/0004_alter_luxpurchase_source.py new file mode 100644 index 0000000..0eab270 --- /dev/null +++ b/app/budget/migrations/0004_alter_luxpurchase_source.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.6 on 2022-11-12 10:46 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('budget', '0003_alter_luxpurchase_category_alter_luxpurchase_source'), + ] + + operations = [ + migrations.AlterField( + model_name='luxpurchase', + name='source', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='budget.luxsource'), + ), + ] diff --git a/app/budget/models.py b/app/budget/models.py index acf2b69..f4c6ec0 100644 --- a/app/budget/models.py +++ b/app/budget/models.py @@ -1,4 +1,10 @@ +import calendar +import datetime from django.db import models +from django.db.models import Sum +from django.urls import reverse +from django.utils import timezone + class LuxSource(models.Model): name = models.CharField(max_length=200) @@ -7,11 +13,29 @@ class LuxSource(models.Model): def __str__(self): return self.name + +class LuxPurchaseStatsManager(models.Manager): + + def get_monthly_spending(self, month=timezone.now().month): + last_day = calendar.monthrange(timezone.now().year, month)[1] + start_date = datetime.date(timezone.now().year, month, 1) + end_date = datetime.date(timezone.now().year, month, last_day) + return self.filter(date_recorded__range=(start_date, end_date)).aggregate(Sum('amount')) + + def get_monthly_spending_by_category(self, cat, number_of_months=1): + today = timezone.now() + month = today.replace(day=1).month + start_month = month - number_of_months + 1 + start_date = datetime.date(timezone.now().year, start_month, 1) + last_day = calendar.monthrange(timezone.now().year, month)[1] + end_date = datetime.date(timezone.now().year, month, last_day) + return self.filter(date_recorded__range=(start_date, end_date)).filter(category=cat).aggregate(Sum('amount')) + class LuxPurchase(models.Model): - amount = models.IntegerField() + amount = models.DecimalField(max_digits=6, decimal_places=2) source = models.ForeignKey(LuxSource, on_delete=models.CASCADE) CATEGORY = ( - (0, 'Grocery and Home'), + (0, 'Grocery & Home'), (1, 'Gas'), (2, 'Bus'), (3, 'Lodging'), @@ -27,5 +51,11 @@ class LuxPurchase(models.Model): ordering = ('-date_recorded',) def __str__(self): - return self.name + return "%s - %s" %(self.amount, self.source.name) + + def get_absolute_url(self): + return reverse("luxbudget:detail", kwargs={"pk": self.pk}) + + objects = models.Manager() # The default manager. + stats = LuxPurchaseStatsManager() diff --git a/app/budget/templates/budget/base.html b/app/budget/templates/budget/base.html index e17813a..355c911 100644 --- a/app/budget/templates/budget/base.html +++ b/app/budget/templates/budget/base.html @@ -23,7 +23,7 @@ </head> <body> <nav> - <span class="nav-item"><a href="{% url 'luxtrade:list' %}">Home</a></span> + <span class="nav-item"><a href="{% url 'luxbudget:list' %}">Home</a></span> </nav> {% block content %} {% endblock %} diff --git a/app/budget/templates/budget/luxpurchase_list.html b/app/budget/templates/budget/luxpurchase_list.html new file mode 100644 index 0000000..765834a --- /dev/null +++ b/app/budget/templates/budget/luxpurchase_list.html @@ -0,0 +1,46 @@ +{% extends 'budget/base.html' %} +{% load typogrify_tags %} + {% block pagetitle %}Luxagraf - Record Purchase{% endblock %} + {% block content %} + <a href="record" class="btn" >Add New</a> + <h3>Recent Purchases</h3> + <table> + <thead> + <tr> + <th>Date</th> + <th>Store</th> + <th>Category</th> + <th>Amount</th> + </tr> + </thead> + {% for object in object_list %} + <tr> + <td><a href="{{object.get_absolute_url}}">{{object.date_recorded|date:"m/j"}}</a></td> + <td>{{object.source.name}}</td> + <td>{{object.get_category_display}}</td> + <td>${{object.amount}}</td> + </tr> + {% endfor %} + <tr> + <td> </td> + </tr> + <tr> + <td></td> + <td></td> + <td class="right">{{month}} Total:</td> + <td>${{monthly_spending.amount__sum}}</td> + </tr> + </table> + + <h3>Previous Monthly Spending</h3> + {{month_1}}: {{monthly_spending_1.amount__sum}} + {{month_2}}: {{monthly_spending_2.amount__sum}} + {{month_3}}: {{monthly_spending_3.amount__sum}} + + + <h3>Spending by Category (Last 3 Months)</h3> + + {{cat.amount__sum}} + {% endblock %} + + diff --git a/app/budget/templates/budget/update_form.html b/app/budget/templates/budget/update_form.html new file mode 100644 index 0000000..b19efaa --- /dev/null +++ b/app/budget/templates/budget/update_form.html @@ -0,0 +1,20 @@ +{% extends 'budget/base.html' %} +{% load typogrify_tags %} +{% block content %} + <form id="id_form" action="" method="post" class="big">{% csrf_token %} + {% for field in form %} + <fieldset> + {{ field.errors }} + {% if field.name == 'status'%} + <label class="hide" for="id_status">Status:</label>{{ field }} + {% else %} + {{ field.label_tag }} {{ field }} + {% endif %} + {% if field.help_text %} + <p class="help">{{ field.help_text|safe }}</p> + {% endif %} + </fieldset> +{% endfor %} + <input type="submit" name="post" class="btn" value="update purchase"/> + </form> + {% endblock %} diff --git a/app/budget/urls.py b/app/budget/urls.py index 86c56a2..92fc184 100644 --- a/app/budget/urls.py +++ b/app/budget/urls.py @@ -12,7 +12,7 @@ urlpatterns = [ ), path( 'purchase/<pk>', - views.PurchaseModelFormView.as_view(), + views.PurchaseUpdateView.as_view(), name='detail' ), path( diff --git a/app/budget/views.py b/app/budget/views.py index 3743eaf..e291bde 100644 --- a/app/budget/views.py +++ b/app/budget/views.py @@ -1,5 +1,7 @@ +import datetime from django.shortcuts import render from django.views.generic.edit import CreateView, UpdateView +from django.utils import timezone from utils.views import PaginatedListView from .models import LuxPurchase @@ -9,5 +11,35 @@ class PurchaseModelFormView(CreateView): success_url = '/spending/' template_name = 'budget/create_form.html' + +class PurchaseUpdateView(UpdateView): + model = LuxPurchase + fields = ['amount', 'source', 'category'] + success_url = '/spending/' + template_name = 'budget/update_form.html' + + class LuxPurchaseListView(PaginatedListView): - pass + model = LuxPurchase + + def get_context_data(self, **kwargs): + ''' + Get Monthly Spending for a nice bar chart + ''' + # Call the base implementation first to get a context + context = super(LuxPurchaseListView, self).get_context_data(**kwargs) + context['monthly_spending'] = LuxPurchase.stats.get_monthly_spending() + today = timezone.now() + first = today.replace(day=1) + month_1 = first - datetime.timedelta(days=1) + month_2 = month_1.replace(day=1) - datetime.timedelta(days=1) + month_3 = month_2.replace(day=1) - datetime.timedelta(days=1) + context['month'] = today.strftime('%h') + context['monthly_spending_1'] = LuxPurchase.stats.get_monthly_spending(month_1.month) + context['month_1'] = month_1.strftime('%h') + context['monthly_spending_2'] = LuxPurchase.stats.get_monthly_spending(month_2.month) + context['month_2'] = month_2.strftime('%h') + context['monthly_spending_3'] = LuxPurchase.stats.get_monthly_spending(month_3.month) + context['month_3'] = month_3.strftime('%h') + context['cat'] = LuxPurchase.stats.get_monthly_spending_by_category(1, 3) + return context |