Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/economy/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import faker
from django.contrib.auth.models import User
from django.utils import timezone
from utils.slugs import unique_slugify

from camps.models import Camp
from teams.models import Team
from utils.slugs import unique_slugify

from .models import Bank
from .models import BankAccount
Expand All @@ -32,6 +32,7 @@

fake = faker.Faker()


class BankFactory(factory.django.DjangoModelFactory):
class Meta:
model = Bank
Expand Down Expand Up @@ -530,6 +531,7 @@ class Meta:
address = factory.Faker("address", locale="dk_DK")
notes = factory.Faker("text")


class ExpenseFactory(factory.django.DjangoModelFactory):
"""Factory for creating expense data."""

Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,65 @@
# Generated by Django 4.2.21 on 2025-06-09 18:13
from __future__ import annotations

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


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('economy', '0043_coinifysettlement'),
("economy", "0043_coinifysettlement"),
]

operations = [
migrations.AddField(
model_name='posreport',
name='bank_responsible_end',
field=models.ForeignKey(blank=True, help_text='The banker responsible for the day end count of this PosReport', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pos_report_banker_end', to=settings.AUTH_USER_MODEL),
model_name="posreport",
name="bank_responsible_end",
field=models.ForeignKey(
blank=True,
help_text="The banker responsible for the day end count of this PosReport",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="pos_report_banker_end",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name='posreport',
name='bank_responsible_start',
field=models.ForeignKey(blank=True, help_text='The banker responsible for the day start count of this PosReport', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pos_report_banker_start', to=settings.AUTH_USER_MODEL),
model_name="posreport",
name="bank_responsible_start",
field=models.ForeignKey(
blank=True,
help_text="The banker responsible for the day start count of this PosReport",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="pos_report_banker_start",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name='posreport',
name='pos_responsible_end',
field=models.ForeignKey(blank=True, help_text='The pos responsible for the day end count of this PosReport', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pos_report_pos_end', to=settings.AUTH_USER_MODEL),
model_name="posreport",
name="pos_responsible_end",
field=models.ForeignKey(
blank=True,
help_text="The pos responsible for the day end count of this PosReport",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="pos_report_pos_end",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name='posreport',
name='pos_responsible_start',
field=models.ForeignKey(blank=True, help_text='The pos responsible for the day start count of this PosReport', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pos_report_pos_start', to=settings.AUTH_USER_MODEL),
model_name="posreport",
name="pos_responsible_start",
field=models.ForeignKey(
blank=True,
help_text="The pos responsible for the day start count of this PosReport",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="pos_report_pos_start",
to=settings.AUTH_USER_MODEL,
),
),
]
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Generated by Django 4.2.21 on 2025-06-09 18:13
from __future__ import annotations

from django.db import migrations

Expand All @@ -14,9 +15,8 @@ def populate_pos_people(apps, schema_editor) -> None:


class Migration(migrations.Migration):

dependencies = [
('economy', '0044_posreport_bank_responsible_end_and_more'),
("economy", "0044_posreport_bank_responsible_end_and_more"),
]

operations = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# Generated by Django 4.2.21 on 2025-06-09 18:59
from __future__ import annotations

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('economy', '0045_populate_bank_and_pos_responsible'),
("economy", "0045_populate_bank_and_pos_responsible"),
]

operations = [
migrations.RemoveField(
model_name='posreport',
name='bank_responsible',
model_name="posreport",
name="bank_responsible",
),
migrations.RemoveField(
model_name='posreport',
name='pos_responsible',
model_name="posreport",
name="pos_responsible",
),
]
55 changes: 27 additions & 28 deletions src/economy/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import OuterRef
from django.db.models import Q
from django.db.models import Prefetch
from django.db.models import Q
from django.db.models import Sum
from django.http import HttpResponse
from django.http import HttpResponseRedirect
Expand Down Expand Up @@ -67,8 +66,8 @@ def get_context_data(self, **kwargs):
).count()
reimbursement_total = 0
for reimbursement in Reimbursement.objects.filter(
reimbursement_user=self.request.user,
camp=self.camp,
reimbursement_user=self.request.user,
camp=self.camp,
):
reimbursement_total += reimbursement.amount
context["reimbursement_total"] = reimbursement_total
Expand Down Expand Up @@ -158,18 +157,14 @@ class ChainListView(CampViewMixin, RaisePermissionRequiredMixin, ListView):
permission_required = "camps.expense_create_permission"

def get_queryset(self):
queryset = (Chain.objects
.filter(credebtors__expenses__camp=self.camp)
.order_by('name'))
queryset = Chain.objects.filter(credebtors__expenses__camp=self.camp).order_by("name")

return queryset

def get_context_data(self, **kwargs):
"""Add chains with expenses in past years"""
context = super().get_context_data(**kwargs)
context['past_year_chains'] = (Chain.objects
.filter(~Q(credebtors__expenses__camp=self.camp))
.order_by('name'))
context["past_year_chains"] = Chain.objects.filter(~Q(credebtors__expenses__camp=self.camp)).order_by("name")
return context


Expand Down Expand Up @@ -219,23 +214,27 @@ class CredebtorListView(
permission_required = "camps.expense_create_permission"

def get_queryset(self):
expenses=Expense.objects.filter(camp=self.camp)
revenues=Revenue.objects.filter(camp=self.camp)
return (Credebtor.objects.filter(
chain=self.chain
).prefetch_related(
Prefetch(
'expenses',
queryset=expenses,
to_attr="current_expenses",
expenses = Expense.objects.filter(camp=self.camp)
revenues = Revenue.objects.filter(camp=self.camp)
return (
Credebtor.objects.filter(
chain=self.chain,
)
).prefetch_related(
Prefetch(
'revenues',
queryset=revenues,
to_attr="current_revenues",
.prefetch_related(
Prefetch(
"expenses",
queryset=expenses,
to_attr="current_expenses",
),
)
))
.prefetch_related(
Prefetch(
"revenues",
queryset=revenues,
to_attr="current_revenues",
),
)
)

def get_context_data(self, **kwargs):
"""Add chain to context."""
Expand Down Expand Up @@ -422,9 +421,9 @@ class ReimbursementCreateView(CampViewMixin, ExpensePermissionMixin, CreateView)
def get(self, request, *args, **kwargs):
"""Check if this user has any approved and un-reimbursed expenses."""
if not request.user.expenses.filter(
reimbursement__isnull=True,
approved=True,
paid_by_bornhack=False,
reimbursement__isnull=True,
approved=True,
paid_by_bornhack=False,
):
messages.error(
request,
Expand Down
25 changes: 25 additions & 0 deletions src/program/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django.urls import reverse

from utils.tests import BornhackTestBase
from program.models import Event

class TestFeedbackCreateView(BornhackTestBase):
"""Test FeedbackCreateView"""

@classmethod
def setUpTestData(cls) -> None:
"""Test setup."""
super().setUpTestData()
cls.bootstrap.create_camp_proposals(cls.camp, cls.bootstrap.event_types)

def test_create_feedback_requires_login(self) -> None:
"""Test creating feedback for an event requires user to be signed in"""
event = Event.objects.all().first()
kwargs = {"camp_slug": self.camp.slug, "event_slug": event.slug}
url = reverse("program:event_feedback_create", kwargs=kwargs)
expected = reverse("program:event_detail", kwargs=kwargs)

response = self.client.get(url)

self.assertRedirects(response, expected)

15 changes: 15 additions & 0 deletions src/program/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,21 @@ class FeedbackCreateView(LoginRequiredMixin, EventViewMixin, CreateView):

def setup(self, *args, **kwargs) -> None:
super().setup(*args, **kwargs)
if not self.request.user.is_authenticated:
messages.error(
self.request,
"You must be logged in to provide Event Feedback",
)
raise RedirectException(
reverse(
"program:event_detail",
kwargs={
"camp_slug": self.camp.slug,
"event_slug": self.event.slug,
},
),
)

if models.EventFeedback.objects.filter(
event=self.event,
user=self.request.user,
Expand Down
1 change: 1 addition & 0 deletions src/utils/bootstrap/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2379,6 +2379,7 @@ def bootstrap_tests(self) -> None:
ticket_types,
)
self.create_prize_ticket(camp, ticket_types)
self.create_camp_tracks(camp)

teams[year] = self.create_camp_teams(camp)
self.create_camp_team_memberships(camp, teams[year], self.users)
Expand Down
Loading