Initial claims system setup
This commit is contained in:
308
claims/views.py
Normal file
308
claims/views.py
Normal file
@@ -0,0 +1,308 @@
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
||||
from django.forms import formset_factory
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.views import View
|
||||
from django.views.generic import ListView, TemplateView
|
||||
|
||||
from .forms import (
|
||||
ClaimDecisionForm,
|
||||
ClaimLineForm,
|
||||
ClaimantForm,
|
||||
DeleteUserForm,
|
||||
UserManagementForm,
|
||||
UserPermissionForm,
|
||||
)
|
||||
from .models import Claim, ClaimLog
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class SubmitClaimView(View):
|
||||
template_name = "claims/submit_claim.html"
|
||||
max_extra_forms = 5
|
||||
|
||||
def get_extra_forms(self):
|
||||
try:
|
||||
count = int(self.request.GET.get("forms", 2))
|
||||
except (TypeError, ValueError):
|
||||
count = 2
|
||||
return max(1, min(count, self.max_extra_forms))
|
||||
|
||||
def build_formset(self, *, data=None, files=None, extra=0):
|
||||
FormSet = formset_factory(
|
||||
ClaimLineForm,
|
||||
extra=extra,
|
||||
min_num=1,
|
||||
validate_min=True,
|
||||
)
|
||||
return FormSet(data=data, files=files, prefix="claim_lines")
|
||||
|
||||
def get_claimant_initial(self):
|
||||
initial = {}
|
||||
user = self.request.user
|
||||
if user.is_authenticated:
|
||||
initial["full_name"] = user.get_full_name() or user.get_username()
|
||||
initial["email"] = user.email
|
||||
last_claim = user.claims_submitted.order_by("-created_at").first()
|
||||
if last_claim:
|
||||
initial["account_number"] = last_claim.account_number
|
||||
return initial
|
||||
|
||||
def get(self, request):
|
||||
extra = self.get_extra_forms()
|
||||
formset = self.build_formset(extra=extra)
|
||||
claimant_form = ClaimantForm(initial=self.get_claimant_initial())
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
{
|
||||
"formset": formset,
|
||||
"claimant_form": claimant_form,
|
||||
"extra_forms": extra,
|
||||
"max_extra_forms": self.max_extra_forms,
|
||||
},
|
||||
)
|
||||
|
||||
def post(self, request):
|
||||
formset = self.build_formset(data=request.POST, files=request.FILES)
|
||||
claimant_form = ClaimantForm(request.POST)
|
||||
if formset.is_valid() and claimant_form.is_valid():
|
||||
claimant_data = claimant_form.cleaned_data
|
||||
created = 0
|
||||
for form in formset:
|
||||
if not form.cleaned_data:
|
||||
continue
|
||||
description = form.cleaned_data.get("description")
|
||||
amount = form.cleaned_data.get("amount")
|
||||
if not description or amount is None:
|
||||
continue
|
||||
|
||||
claim = Claim(
|
||||
full_name=claimant_data["full_name"],
|
||||
email=claimant_data["email"],
|
||||
account_number=claimant_data["account_number"],
|
||||
amount=amount,
|
||||
currency=form.cleaned_data.get("currency") or Claim.Currency.SEK,
|
||||
description=description,
|
||||
receipt=form.cleaned_data.get("receipt"),
|
||||
project=form.cleaned_data.get("project"),
|
||||
submitted_by=request.user if request.user.is_authenticated else None,
|
||||
)
|
||||
claim.save()
|
||||
claim.add_log(
|
||||
action=ClaimLog.Action.CREATED,
|
||||
performed_by=claim.submitted_by,
|
||||
to_status=Claim.Status.PENDING,
|
||||
)
|
||||
created += 1
|
||||
|
||||
if created:
|
||||
messages.success(request, f"{created} utlägg skickade in.")
|
||||
return redirect(reverse("claims:admin-list"))
|
||||
|
||||
messages.error(request, "Inga utlägg kunde sparas. Fyll i minst en rad.")
|
||||
else:
|
||||
messages.error(request, "Kunde inte spara utläggen. Kontrollera formuläret.")
|
||||
|
||||
extra = min(formset.total_form_count(), self.max_extra_forms)
|
||||
return render(
|
||||
request,
|
||||
self.template_name,
|
||||
{
|
||||
"formset": formset,
|
||||
"claimant_form": claimant_form,
|
||||
"extra_forms": extra,
|
||||
"max_extra_forms": self.max_extra_forms,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ClaimAdminListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
template_name = "claims/admin_list.html"
|
||||
context_object_name = "claims"
|
||||
permission_required = "claims.view_claim"
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = (
|
||||
Claim.objects.select_related("submitted_by", "project")
|
||||
.prefetch_related("logs__performed_by")
|
||||
.all()
|
||||
)
|
||||
status = self.request.GET.get("status")
|
||||
if status in {choice[0] for choice in Claim.Status.choices}:
|
||||
queryset = queryset.filter(status=status)
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["status_filter"] = self.request.GET.get("status", "all")
|
||||
context["status_choices"] = Claim.Status.choices
|
||||
context["decision_choices"] = ClaimDecisionForm().fields["action"].choices
|
||||
context["can_change"] = self.request.user.has_perm("claims.change_claim")
|
||||
return context
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not request.user.has_perm("claims.change_claim"):
|
||||
messages.error(request, "Du har inte behörighet att uppdatera utlägg.")
|
||||
return redirect(request.get_full_path())
|
||||
|
||||
form = ClaimDecisionForm(request.POST)
|
||||
if not form.is_valid():
|
||||
for field_errors in form.errors.values():
|
||||
for error in field_errors:
|
||||
messages.error(request, error)
|
||||
return redirect(request.get_full_path())
|
||||
|
||||
claim = get_object_or_404(Claim, pk=form.cleaned_data["claim_id"])
|
||||
action = form.cleaned_data["action"]
|
||||
decision_note = form.cleaned_data.get("decision_note", "")
|
||||
previous_status = claim.status
|
||||
claim.decision_note = decision_note
|
||||
|
||||
if action == ClaimDecisionForm.ACTION_APPROVE:
|
||||
claim.status = Claim.Status.APPROVED
|
||||
messages.success(request, f"{claim} markerades som godkänd.")
|
||||
else:
|
||||
claim.status = Claim.Status.REJECTED
|
||||
messages.warning(request, f"{claim} markerades som nekad.")
|
||||
|
||||
claim.save(update_fields=["status", "decision_note", "updated_at"])
|
||||
claim.add_log(
|
||||
action=ClaimLog.Action.STATUS_CHANGED,
|
||||
performed_by=request.user,
|
||||
from_status=previous_status,
|
||||
to_status=claim.status,
|
||||
note=decision_note,
|
||||
)
|
||||
return redirect(request.get_full_path())
|
||||
|
||||
|
||||
class ClaimExportMenuView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView):
|
||||
template_name = "claims/export_placeholder.html"
|
||||
permission_required = "claims.view_claim"
|
||||
|
||||
|
||||
class MyClaimsView(LoginRequiredMixin, ListView):
|
||||
template_name = "claims/my_claims.html"
|
||||
context_object_name = "claims"
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
Claim.objects.filter(submitted_by=self.request.user)
|
||||
.select_related("project")
|
||||
.prefetch_related("logs__performed_by")
|
||||
.order_by("-created_at")
|
||||
)
|
||||
|
||||
|
||||
class UserManagementView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView):
|
||||
template_name = "claims/user_management.html"
|
||||
permission_required = "auth.view_user"
|
||||
|
||||
def _ensure_perm(self, perm_codename):
|
||||
perm = f"auth.{perm_codename}"
|
||||
if not self.request.user.has_perm(perm):
|
||||
messages.error(self.request, "Du saknar behörighet för åtgärden.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
users = User.objects.order_by("username")
|
||||
rows = []
|
||||
for user in users:
|
||||
rows.append(
|
||||
{
|
||||
"user": user,
|
||||
"permission_form": UserPermissionForm(
|
||||
initial={
|
||||
"user_id": user.id,
|
||||
"is_staff": user.is_staff,
|
||||
"grant_view": user.has_perm("claims.view_claim"),
|
||||
"grant_change": user.has_perm("claims.change_claim"),
|
||||
}
|
||||
),
|
||||
"delete_form": None
|
||||
if user == self.request.user or user.is_superuser
|
||||
else DeleteUserForm(initial={"user_id": user.id}),
|
||||
}
|
||||
)
|
||||
context["user_rows"] = rows
|
||||
context["create_form"] = kwargs.get("create_form") or UserManagementForm()
|
||||
return context
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
action = request.POST.get("action")
|
||||
|
||||
if action == "create":
|
||||
if not self._ensure_perm("add_user"):
|
||||
return redirect(request.path)
|
||||
form = UserManagementForm(request.POST)
|
||||
if form.is_valid():
|
||||
user = User.objects.create_user(
|
||||
username=form.cleaned_data["username"],
|
||||
password=form.cleaned_data["password1"],
|
||||
email=form.cleaned_data.get("email", ""),
|
||||
first_name=form.cleaned_data.get("first_name", ""),
|
||||
last_name=form.cleaned_data.get("last_name", ""),
|
||||
is_staff=form.cleaned_data.get("is_staff", False),
|
||||
)
|
||||
self._set_perm(user, "claims.view_claim", form.cleaned_data.get("grant_view", False))
|
||||
self._set_perm(user, "claims.change_claim", form.cleaned_data.get("grant_change", False))
|
||||
messages.success(request, f"Användaren {user.username} skapades.")
|
||||
return redirect(request.path)
|
||||
return self.render_to_response(self.get_context_data(create_form=form))
|
||||
|
||||
elif action == "update":
|
||||
if not self._ensure_perm("change_user"):
|
||||
return redirect(request.path)
|
||||
form = UserPermissionForm(request.POST)
|
||||
if form.is_valid():
|
||||
user = get_object_or_404(User, pk=form.cleaned_data["user_id"])
|
||||
if user == request.user and not form.cleaned_data["is_staff"]:
|
||||
messages.error(request, "Du kan inte ta bort din egen staff-status.")
|
||||
return redirect(request.path)
|
||||
user.is_staff = form.cleaned_data["is_staff"]
|
||||
user.save(update_fields=["is_staff"])
|
||||
self._set_perm(user, "claims.view_claim", form.cleaned_data["grant_view"])
|
||||
self._set_perm(user, "claims.change_claim", form.cleaned_data["grant_change"])
|
||||
messages.success(request, f"Behörigheter uppdaterades för {user.username}.")
|
||||
else:
|
||||
messages.error(request, "Kunde inte uppdatera behörigheter.")
|
||||
return redirect(request.path)
|
||||
|
||||
elif action == "delete":
|
||||
if not self._ensure_perm("delete_user"):
|
||||
return redirect(request.path)
|
||||
form = DeleteUserForm(request.POST)
|
||||
if form.is_valid():
|
||||
user = get_object_or_404(User, pk=form.cleaned_data["user_id"])
|
||||
if user == request.user:
|
||||
messages.error(request, "Du kan inte ta bort ditt eget konto.")
|
||||
elif user.is_superuser:
|
||||
messages.error(request, "Du kan inte ta bort en superuser via detta gränssnitt.")
|
||||
else:
|
||||
user.delete()
|
||||
messages.warning(request, "Användaren togs bort.")
|
||||
return redirect(request.path)
|
||||
|
||||
messages.error(request, "Okänd åtgärd.")
|
||||
return redirect(request.path)
|
||||
|
||||
@staticmethod
|
||||
def _set_perm(user, perm_label, should_have):
|
||||
app_label, codename = perm_label.split(".")
|
||||
perm = Permission.objects.filter(
|
||||
content_type__app_label=app_label,
|
||||
codename=codename,
|
||||
).first()
|
||||
if not perm:
|
||||
return
|
||||
if should_have:
|
||||
user.user_permissions.add(perm)
|
||||
else:
|
||||
user.user_permissions.remove(perm)
|
||||
Reference in New Issue
Block a user