Compare commits

...

2 Commits

Author SHA1 Message Date
3b61061e4c paperwork: Add two stage definition/version selection in Certification admin 2023-04-01 11:37:49 -04:00
1e4fc52531 Re-add ExpressionWrapper to CertificationVersionManager annotations
Not sure why I removed them, but things sure are broken without them
2023-04-01 01:07:17 -04:00
6 changed files with 120 additions and 3 deletions

View File

@ -13,6 +13,7 @@ from .models import (
SpecialProgram,
Waiver,
)
from .forms import CertificationForm
from .certification_emails import all_certification_emails
@ -65,6 +66,7 @@ class CertificationDefinitionAdmin(admin.ModelAdmin):
@admin.register(Certification)
class CertificationAdmin(admin.ModelAdmin):
form = CertificationForm
search_fields = [
"name",
"certification_version__definition__certification_name",

View File

@ -0,0 +1,42 @@
from dal import autocomplete
from django.db.models.functions import Concat
from django.db.models import Q, Value, CharField
from .models import CertificationVersion
class CertificationVersionAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.has_perm("membershipworks.view_certification_version"):
return CertificationVersion.objects.none()
qs = CertificationVersion.objects.alias(
version_str=Concat(
"major",
Value("."),
"minor",
Value("."),
"patch",
output_field=CharField(),
),
)
certification_definition = self.forwarded.get("certification_definition", None)
if certification_definition:
qs = qs.filter(definition=certification_definition)
if self.q:
qs = qs.filter(
Q(version_str__istartswith=self.q)
| Q(prerelease__istartswith=self.q)
| Q(approval_date__istartswith=self.q)
)
return qs
def get_result_label(self, result: CertificationVersion) -> str:
return str(result.semantic_version())
def get_selected_result_label(self, result: CertificationVersion) -> str:
return str(result)

51
paperwork/forms.py Normal file
View File

@ -0,0 +1,51 @@
from dal import autocomplete
from django import forms
from django.core.exceptions import ValidationError
from .models import CertificationDefinition, Certification
class CertificationForm(forms.ModelForm):
certification_definition = forms.ModelChoiceField(
queryset=CertificationDefinition.objects.all()
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = kwargs.get("instance")
if instance:
self.fields[
"certification_definition"
].initial = instance.certification_version.definition
def clean(self):
cleaned_data = super().clean()
certification_version = cleaned_data.get("certification_version")
certification_definition = cleaned_data.get("certification_definition")
if certification_version.definition != certification_definition:
raise ValidationError(
"Certification Version did not match Certification Definition!"
)
class Media:
js = ("paperwork/certification-form-clear-autocomplete.js",)
class Meta:
model = Certification
fields = [
"certification_definition",
"certification_version",
"name",
"member",
"certified_by",
"date",
"notes",
]
widgets = {
"certification_version": autocomplete.ModelSelect2(
url="paperwork:certification_version_autocomplete",
forward=["certification_definition"],
)
}

View File

@ -2,7 +2,7 @@ import re
from semver import VersionInfo
from django.db import models
from django.db.models import OuterRef, Q, Subquery
from django.db.models import OuterRef, Q, ExpressionWrapper, Subquery
from django.core.validators import RegexValidator
from membershipworks.models import Member, Flag as MembershipWorksFlag
@ -110,9 +110,15 @@ class CertificationVersionManager(models.Manager):
qs = super().get_queryset()
latest = qs.filter(definition__pk=OuterRef("definition__pk")).reverse()
return qs.annotate(
is_latest=Q(pk=Subquery(latest.values("pk")[:1])),
is_latest=ExpressionWrapper(
Q(pk=Subquery(latest.values("pk")[:1])),
output_field=models.BooleanField(),
),
# TODO: should do a more correct comparison than just major version
is_current=Q(major=Subquery(latest.values("major")[:1])),
is_current=ExpressionWrapper(
Q(major=Subquery(latest.values("major")[:1])),
output_field=models.BooleanField(),
),
)

View File

@ -0,0 +1,10 @@
window.addEventListener('load', function() {
// Bind on certification_definition field change
django.jQuery(':input[name$=certification_definition]').on('change', function() {
// Get the field prefix, ie. if this comes from a formset form
var prefix = django.jQuery(this).getFormPrefix();
// Clear the autocomplete with the same prefix
django.jQuery(':input[name=' + prefix + 'certification_version]').val(null).trigger('change');
});
});

View File

@ -1,6 +1,7 @@
from django.urls import path
from . import views
from . import autocomplete_views
app_name = "paperwork"
@ -20,4 +21,9 @@ urlpatterns = [
views.certification_pdf,
name="certification_pdf",
),
path(
"certifications/version_autocomplete",
autocomplete_views.CertificationVersionAutocomplete.as_view(),
name="certification_version_autocomplete",
),
]