paperwork: Add access verification report
This commit is contained in:
parent
43f992e2c3
commit
c07e3ac07a
@ -24,6 +24,11 @@ class PaperworkDashboardFragment(dashboard.LinksCardDashboardFragment):
|
|||||||
reverse("paperwork:instructors-and-vendor-report"),
|
reverse("paperwork:instructors-and-vendor-report"),
|
||||||
permission="paperwork.view_instructororvendor",
|
permission="paperwork.view_instructororvendor",
|
||||||
),
|
),
|
||||||
|
Link(
|
||||||
|
"Access Verification",
|
||||||
|
reverse("paperwork:access-verification-report"),
|
||||||
|
permission="paperwork.view_certification",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
member = Member.from_user(self.request.user)
|
member = Member.from_user(self.request.user)
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
{% extends "base.dj.html" %}
|
||||||
|
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
|
||||||
|
{% block title %}Access Verification{% endblock %}
|
||||||
|
{% block admin_link %}
|
||||||
|
{% url 'admin:paperwork_certification_changelist' %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
{% include "cmsmanage/components/download_table.dj.html" %}
|
||||||
|
{% render_table table %}
|
||||||
|
{% endblock %}
|
@ -35,4 +35,9 @@ urlpatterns = [
|
|||||||
views.InstructorOrVendorReport.as_view(),
|
views.InstructorOrVendorReport.as_view(),
|
||||||
name="instructors-and-vendor-report",
|
name="instructors-and-vendor-report",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"access-verification",
|
||||||
|
views.AccessVerificationReport.as_view(),
|
||||||
|
name="access-verification-report",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -2,6 +2,9 @@ from django.conf import settings
|
|||||||
from django.contrib import staticfiles
|
from django.contrib import staticfiles
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models import Case, Q, Value, When
|
||||||
|
from django.db.models.functions import Concat
|
||||||
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
|
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.views.generic import ListView
|
from django.views.generic import ListView
|
||||||
@ -15,7 +18,13 @@ from django_tables2.export.views import ExportMixin
|
|||||||
|
|
||||||
from membershipworks.models import Member
|
from membershipworks.models import Member
|
||||||
|
|
||||||
from .models import Certification, Department, InstructorOrVendor, Waiver
|
from .models import (
|
||||||
|
Certification,
|
||||||
|
CertificationVersion,
|
||||||
|
Department,
|
||||||
|
InstructorOrVendor,
|
||||||
|
Waiver,
|
||||||
|
)
|
||||||
|
|
||||||
WIKI_URL = settings.WIKI_URL
|
WIKI_URL = settings.WIKI_URL
|
||||||
|
|
||||||
@ -186,3 +195,132 @@ class InstructorOrVendorReport(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ShopAccessErrorColumn(tables.Column):
|
||||||
|
def td_class(value):
|
||||||
|
if value.startswith("Has access but"):
|
||||||
|
return "table-danger"
|
||||||
|
elif value.startswith("Has cert but"):
|
||||||
|
return "table-warning"
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
attrs = {"td": {"class": td_class}}
|
||||||
|
|
||||||
|
|
||||||
|
class AccessVerificationTable(tables.Table):
|
||||||
|
account_name = tables.Column()
|
||||||
|
access_card = tables.Column()
|
||||||
|
billing_method = tables.Column()
|
||||||
|
join_date = tables.DateColumn()
|
||||||
|
renewal_date = tables.DateColumn()
|
||||||
|
access_front_door = tables.BooleanColumn(verbose_name="Front Door")
|
||||||
|
access_studio_space = tables.BooleanColumn(verbose_name="Studio Space")
|
||||||
|
wood_shop_error = ShopAccessErrorColumn()
|
||||||
|
metal_shop_error = ShopAccessErrorColumn()
|
||||||
|
extended_hours_error = ShopAccessErrorColumn()
|
||||||
|
extended_hours_shops_error = ShopAccessErrorColumn()
|
||||||
|
storage_closet_error = ShopAccessErrorColumn()
|
||||||
|
|
||||||
|
|
||||||
|
class AccessVerificationReport(
|
||||||
|
ExportMixin,
|
||||||
|
SingleTableMixin,
|
||||||
|
PermissionRequiredMixin,
|
||||||
|
ListView,
|
||||||
|
):
|
||||||
|
permission_required = "paperwork.view_certification"
|
||||||
|
template_name = "paperwork/access_verification_report.dj.html"
|
||||||
|
table_class = AccessVerificationTable
|
||||||
|
export_formats = ("csv", "xlsx", "ods")
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
# TODO: could be done with subqueries if membershipworks was not a separate DB
|
||||||
|
def shop_error(access_field: str, shop_name: str):
|
||||||
|
member_list = list(
|
||||||
|
CertificationVersion.objects.filter(
|
||||||
|
is_current=True,
|
||||||
|
definition__department__name=shop_name,
|
||||||
|
certification__member__pk__isnull=False,
|
||||||
|
)
|
||||||
|
.values_list(
|
||||||
|
"certification__member__pk",
|
||||||
|
flat=True,
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
|
return Case(
|
||||||
|
When(
|
||||||
|
Q(**{access_field: True}) & ~Q(uid__in=member_list),
|
||||||
|
Value("Has access but no cert"),
|
||||||
|
),
|
||||||
|
When(
|
||||||
|
Q(**{access_field: False}) & Q(uid__in=member_list),
|
||||||
|
Value("Has cert but no access"),
|
||||||
|
),
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: could be a lot cleaner if membershipworks was not a separate DB
|
||||||
|
storage_closet_members = (
|
||||||
|
Member.objects.filter(
|
||||||
|
Member.objects.has_flag("label", "Volunteer: Desker")
|
||||||
|
| Q(billing_method__startswith="Desker")
|
||||||
|
)
|
||||||
|
.union(
|
||||||
|
*[
|
||||||
|
department.shop_lead_flag.members.all()
|
||||||
|
for department in Department.objects.filter(
|
||||||
|
shop_lead_flag__isnull=False
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.values_list("pk", flat=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
qs = (
|
||||||
|
Member.objects.with_is_active()
|
||||||
|
.filter(is_active=True)
|
||||||
|
.values(
|
||||||
|
"account_name",
|
||||||
|
"billing_method",
|
||||||
|
"join_date",
|
||||||
|
"renewal_date",
|
||||||
|
"access_front_door",
|
||||||
|
"access_studio_space",
|
||||||
|
access_card=Concat(
|
||||||
|
"access_card_facility_code",
|
||||||
|
Value("-", models.TextField()),
|
||||||
|
"access_card_number",
|
||||||
|
),
|
||||||
|
wood_shop_error=shop_error("access_wood_shop", "Wood Shop"),
|
||||||
|
metal_shop_error=shop_error("access_metal_shop", "Metal Shop"),
|
||||||
|
extended_hours_error=shop_error(
|
||||||
|
"access_front_door_and_studio_space_during_extended_hours",
|
||||||
|
"Closure/Lock-Up",
|
||||||
|
),
|
||||||
|
extended_hours_shops_error=shop_error(
|
||||||
|
"access_permitted_shops_during_extended_hours",
|
||||||
|
"Closure/Lock-Up",
|
||||||
|
),
|
||||||
|
storage_closet_error=Case(
|
||||||
|
When(
|
||||||
|
Q(access_storage_closet=True)
|
||||||
|
& ~Q(uid__in=storage_closet_members),
|
||||||
|
Value("Has access but not shop lead or desker"),
|
||||||
|
),
|
||||||
|
default=None,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
Q(access_front_door=False)
|
||||||
|
| Q(access_studio_space=False)
|
||||||
|
| Q(wood_shop_error__isnull=False)
|
||||||
|
| Q(metal_shop_error__isnull=False)
|
||||||
|
| Q(extended_hours_error__isnull=False)
|
||||||
|
| Q(extended_hours_shops_error__isnull=False)
|
||||||
|
| Q(storage_closet_error__isnull=False)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return qs
|
||||||
|
Loading…
Reference in New Issue
Block a user