Skip to content

Commit

Permalink
Implement reimbursements
Browse files Browse the repository at this point in the history
  • Loading branch information
DeD1rk committed Jun 9, 2024
1 parent 0364a1e commit c1c1d0e
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 4 deletions.
4 changes: 4 additions & 0 deletions website/miniconcrexit/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

<a class="nav-link p-2 mx-1" href="{% url 'index' %}">Home</a>

{% if user.is_authenticated %}
<a class="nav-link p-2 mx-1" href="{% url 'reimbursements:index' %}">Reimbursements</a>
{% endif %}

{% if user.is_staff %}
<a class="nav-link p-2 mx-1" href="{% url 'admin:index' %}">Admin</a>
{% endif %}
Expand Down
41 changes: 40 additions & 1 deletion website/reimbursements/admin.py
Original file line number Diff line number Diff line change
@@ -1 +1,40 @@
# Create an admin interface for your model here.
from django.contrib import admin
from django.contrib.admin import register
from django.utils import timezone
from reimbursements import models


@register(models.Reimbursement)
class ReimbursementAdmin(admin.ModelAdmin):
list_display = (
"id",
"created",
"owner",
"date_incurred",
"amount",
"approved",
)
list_filter = ("approved", "created", "date_incurred", "owner")

autocomplete_fields = ["owner"]
readonly_fields = ["approved_by", "approved_at", "created", "updated"]

def save_model(self, request, obj, form, change):
if obj.approved and not form.initial["approved"]:
obj.approved = True
obj.approved_by = request.user
obj.approved_at = timezone.now()

super().save_model(request, obj, form, change)

def get_readonly_fields(self, request, obj=None):
if obj and obj.approved:
return self.readonly_fields + [
"approved",
"amount",
"description",
"receipt",
"date_incurred",
"owner",
]
return self.readonly_fields
60 changes: 60 additions & 0 deletions website/reimbursements/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Generated by Django 4.2.5 on 2023-09-09 20:11

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Reimbursement",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("amount", models.DecimalField(decimal_places=2, max_digits=10)),
("date_incurred", models.DateField()),
("description", models.TextField()),
("receipt", models.FileField(upload_to="receipts/")),
("created", models.DateTimeField(auto_now_add=True)),
("updated", models.DateTimeField(auto_now=True)),
("approved", models.BooleanField(default=False)),
("approved_at", models.DateTimeField(null=True)),
(
"approved_by",
models.ForeignKey(
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="reimbursements_approved",
to=settings.AUTH_USER_MODEL,
),
),
(
"owner",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="reimbursements",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"ordering": ["created"],
},
),
]
36 changes: 35 additions & 1 deletion website/reimbursements/models.py
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
# Create a model here.
from django.db import models


class Reimbursement(models.Model):
owner = models.ForeignKey(
"auth.User",
related_name="reimbursements",
on_delete=models.SET_NULL,
null=True,
blank=False,
)

amount = models.DecimalField(max_digits=10, decimal_places=2)
date_incurred = models.DateField()
description = models.TextField()
receipt = models.FileField(upload_to="receipts/")

created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)

approved = models.BooleanField(default=False)
approved_at = models.DateTimeField(null=True)
approved_by = models.ForeignKey(
"auth.User",
related_name="reimbursements_approved",
on_delete=models.SET_NULL,
editable=False,
null=True,
)

class Meta:
ordering = ["created"]

def __str__(self):
return f"Reimbursement #{self.id}"
10 changes: 10 additions & 0 deletions website/reimbursements/templates/reimbursements/create.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% load django_bootstrap5 %}
{% block body %}
<h1>Request reimbursement</h1>
<form method="post" class="form" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="Submit" %}
</form>
{% endblock %}
41 changes: 41 additions & 0 deletions website/reimbursements/templates/reimbursements/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% extends 'base.html' %}
{% block body %}
<h1>My reimbursements</h1>
<p>
If you have made costs for Thalia, you can submit them here to request reimbursement.
Please note that you can only submit costs for which you have a receipt.
If you have any questions, please contact the treasurer.
</p>
<a href="{% url 'reimbursements:create' %}" class="btn btn-primary mb-3">Submit new reimbursement</a>

{% if object_list %}
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Created</th>
<th scope="col">Date incurred</th>
<th scope="col">Description</th>
<th scope="col">Amount</th>
<th scope="col">Approved</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<th scope="row">{{ object.id }}</th>
<td>{{ object.created }}</td>
<td>{{ object.date_incurred }}</td>
<td>{{ object.description }}</td>
<td>€ {{ object.amount }}</td>
<td>{% if object.approved %}{{ object.approved_at }}{% else %}Pending{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="alert alert-info" role="alert">
<span>You have not submitted any reimbursements yet.</span>
</div>
{% endif %}
{% endblock %}
6 changes: 5 additions & 1 deletion website/reimbursements/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from django.urls import path
from reimbursements.views import CreateReimbursementView, IndexView

app_name = "reimbursements"

urlpatterns = []
urlpatterns = [
path("", IndexView.as_view(), name="index"),
path("create/", CreateReimbursementView.as_view(), name="create"),
]
32 changes: 31 additions & 1 deletion website/reimbursements/views.py
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
# Write your views here. Create templates in `reimbursements/templates/reimbursements/`.
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import CreateView, ListView
from reimbursements.models import Reimbursement


class IndexView(LoginRequiredMixin, ListView):
model = Reimbursement
template_name = "reimbursements/index.html"

def get_queryset(self):
return super().get_queryset().filter(owner=self.request.user)


class CreateReimbursementView(CreateView):
model = Reimbursement
template_name = "reimbursements/create.html"

fields = ["date_incurred", "amount", "description", "receipt"]

success_url = reverse_lazy("reimbursements:index")

def form_valid(self, form):
form.instance.owner = self.request.user
form.save()
return super().form_valid(form)

def get_context_data(self, **kwargs):
context = super().get_context_data()
context["form"].fields["date_incurred"].widget.input_type = "date"
return context

0 comments on commit c1c1d0e

Please sign in to comment.