Skip to content

Commit

Permalink
Interview fix (#852)
Browse files Browse the repository at this point in the history
* script fix

* test fix

* update
  • Loading branch information
Dmi4er4 authored Jun 24, 2024
1 parent adf96fe commit 363aa26
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 47 deletions.
3 changes: 2 additions & 1 deletion apps/admission/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class InvitationCreateInterviewStreamFilter(InterviewStreamFilter):
number_of_misses = django_filters.ChoiceFilter(
label=_("Applicant number of missed interviews"), choices=ApplicantMisses
)
last_name = django_filters.CharFilter(label=_("Last Name"))

@property
def form(self):
Expand All @@ -182,7 +183,7 @@ def form(self):
self._form.helper.layout = Layout(
Row(
Div("campaign", css_class="col-xs-3"), Div("section", css_class="col-xs-3"),
Div("format", css_class="col-xs-3")),
Div("format", css_class="col-xs-3"), Div("last_name", css_class="col-xs-3")),
Row(
Div("track", css_class="col-xs-3"), Div("way_to_interview", css_class="col-xs-3"),
Div("number_of_misses", css_class="col-xs-3"),
Expand Down
19 changes: 11 additions & 8 deletions apps/admission/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def get_ongoing_interview_streams() -> models.QuerySet[InterviewStream]:


def get_applicants_for_invitation(
*, campaign: Campaign, section: str, format=None, track=None, way_to_interview=None,
*, campaign: Campaign, section: str, format=None, last_name=None, track=None, way_to_interview=None,
number_of_misses=None
) -> models.QuerySet[Applicant]:
"""
Expand All @@ -98,15 +98,19 @@ def get_applicants_for_invitation(
.values("applicant_id"))

format_filter = Q()
if format is not None:
if format:
format_filter = Q(interview_format=format) | Q(interview_format=ApplicantInterviewFormats.ANY)

last_name_filter = Q()
if last_name:
last_name_filter = Q(last_name__icontains=last_name)

track_filter = Q()
if track is not None:
track_filter = Q(new_track=(track=="alternative"))
if track:
track_filter = Q(new_track=(track == "alternative"))

way_filter = Q()
if way_to_interview is not None:
if way_to_interview:
if way_to_interview == "exam":
way_filter = Q(status=ApplicantStatuses.PASSED_EXAM)
elif way_to_interview == "olympiad":
Expand All @@ -116,9 +120,8 @@ def get_applicants_for_invitation(
else:
raise ValueError(f"Unsupported value {way_to_interview}")


miss_filter = Q()
if number_of_misses is not None:
if number_of_misses or number_of_misses == 0:
if number_of_misses in range(0, 4):
way_filter = Q(miss_count=number_of_misses)
elif number_of_misses == 4:
Expand All @@ -132,6 +135,7 @@ def get_applicants_for_invitation(
track_filter,
way_filter,
miss_filter,
last_name_filter,
campaign=campaign,
status__in=ApplicantStatuses.RIGHT_BEFORE_INTERVIEW,
)
Expand Down Expand Up @@ -253,7 +257,6 @@ def get_streams(
return {stream: slots for stream, slots in bucket.items() if stream.slots_free_count != 0}



# TODO: change exception type
class InterviewCreateError(APIException):
pass
Expand Down
1 change: 1 addition & 0 deletions apps/admission/templates/admission/interview_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ <h2 class="page-title">{{ applicant.full_name }}{% if request.user.is_curator %}
<div class="additional-info">
Секция: {{ interview.get_section_display }}<br>
Статус собеседования: {{ interview.get_status_display|default_if_none:"<не указан>" }}<br>
Формат собеседования: {{ interview.slot.stream.get_format_display|default_if_none:"<не указан>" }}<br>
</div>
<div class="nav-tabs-horizontal nav-tabs-inverse">
<ul class="nav nav-tabs nav-tabs-solid" data-plugin="nav-tabs" role="tablist">
Expand Down
9 changes: 8 additions & 1 deletion apps/admission/templates/admission/interview_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ <h3 class="panel-title">
<th>Собеседующие</th>
<th>
{% if not filter.form.status.value or filter.form.status.value == "completed" or filter.form.status.value == "agreed" %}
Средний&nbsp;балл{% endif %}</th>
Средний&nbsp;балл
{% else %}
Статус
{% endif %}</th>
<th>Формат</th>
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -89,6 +93,9 @@ <h3 class="panel-title">
<span>{{ interview.get_status_display }}</span>
{% endif %}
</td>
<td>
{{ interview.slot.stream.get_format_display }}
</td>
</tr>
{% empty %}
<tr>
Expand Down
2 changes: 1 addition & 1 deletion apps/admission/tests/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ def test_get_applicants_for_invitation_with_filters(client, settings):
elif applicant.miss_count > 3 and miss_count == 4:
assert applicant in qs
else:
assert applicant not in qs
assert applicant not in qs, f'{applicant=}, {applicant.miss_count=}, {miss_count=}'

@pytest.mark.django_db
def test_get_streams(client, settings):
Expand Down
42 changes: 26 additions & 16 deletions apps/admission/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ class FilterSerializer(serializers.Serializer):
number_of_misses = serializers.ChoiceField(
choices=InvitationCreateInterviewStreamFilter.ApplicantMisses, required=False
)
last_name = serializers.CharField(required=False)

class InputSerializer(serializers.Serializer):
streams = serializers.ListField(
Expand Down Expand Up @@ -294,12 +295,14 @@ def post(self, request, *args, **kwargs):
# Create interview invitations
campaign = filter_serializer.validated_data["campaign"]
section = filter_serializer.validated_data["section"]
format = filter_serializer.validated_data.get("format")
track = filter_serializer.validated_data.get("track")
way_to_interview = filter_serializer.validated_data.get("way_to_interview")
number_of_misses = filter_serializer.validated_data.get("number_of_misses")
applicants = get_applicants_for_invitation(campaign=campaign, section=section, format=format, track=track,
way_to_interview=way_to_interview, number_of_misses=number_of_misses)
format = filter_serializer.validated_data.get("format", "")
track = filter_serializer.validated_data.get("track", "")
way_to_interview = filter_serializer.validated_data.get("way_to_interview", "")
number_of_misses = filter_serializer.validated_data.get("number_of_misses", "")
last_name = filter_serializer.validated_data.get("last_name", "")
applicants = get_applicants_for_invitation(campaign=campaign, section=section, format=format,
last_name=last_name, track=track, way_to_interview=way_to_interview,
number_of_misses=number_of_misses)
applicants = applicants.filter(pk__in=input_serializer.validated_data["ids"])
free_slots = sum(stream.slots_free_count for stream in streams)
if free_slots < len(applicants):
Expand All @@ -318,7 +321,10 @@ def post(self, request, *args, **kwargs):
)
messages.success(request, "Приглашения успешно созданы", extra_tags="timeout")
url = reverse("admission:interviews:invitations:send")
redirect_to = f"{url}?campaign={campaign.id}&section={section}"
redirect_to = f"{url}?campaign={campaign.id}&section={section}&format={format}" \
f"&last_name={last_name}&track={track}&way_to_interview={way_to_interview}" \
f"&number_of_misses={number_of_misses}"
print(redirect_to)
return HttpResponseRedirect(redirect_to)

@staticmethod
Expand Down Expand Up @@ -353,16 +359,18 @@ def get_context_data(self, **kwargs):
filter_serializer = kwargs["filter_serializer"]
campaign = filter_serializer.validated_data["campaign"]
section = filter_serializer.validated_data["section"]
format = filter_serializer.validated_data.get("format")
track = filter_serializer.validated_data.get("track")
way_to_interview = filter_serializer.validated_data.get("way_to_interview")
number_of_misses = filter_serializer.validated_data.get("number_of_misses")
format = filter_serializer.validated_data.get("format", "")
track = filter_serializer.validated_data.get("track", "")
way_to_interview = filter_serializer.validated_data.get("way_to_interview", "")
number_of_misses = filter_serializer.validated_data.get("number_of_misses", "")
last_name = filter_serializer.validated_data.get("last_name", "")
interview_stream_filterset = self.get_interview_stream_filterset(
filter_serializer
)

applicants = (
get_applicants_for_invitation(campaign=campaign, section=section, format=format, track=track,
get_applicants_for_invitation(campaign=campaign, section=section, format=format, last_name=last_name,
track=track,
way_to_interview=way_to_interview, number_of_misses=number_of_misses)
.select_related(
"exam",
Expand All @@ -384,8 +392,9 @@ def get_context_data(self, **kwargs):
page_number = self.request.GET.get("page")
page = paginator.get_page(page_number)
paginator_url = reverse("admission:interviews:invitations:send")
paginator_url = f"{paginator_url}?campaign={campaign.id}&section={section}"

paginator_url = f"{paginator_url}?campaign={campaign.id}&section={section}&format={format}" \
f"&last_name={last_name}&track={track}&way_to_interview={way_to_interview}" \
f"&number_of_misses={number_of_misses}"
context = {
"stream_filter_form": interview_stream_filterset.form,
"stream_form": InterviewStreamInvitationForm(
Expand Down Expand Up @@ -747,7 +756,7 @@ def get(self, request, *args, **kwargs):
user = self.request.user
is_param_lost = any(param not in self.request.GET for param in ["status", "date_from", "date_to"])
if is_param_lost:
today = formats.date_format(timezone.now(), "SHORT_DATE_FORMAT")
today = formats.date_format(now_local(user.branch.get_timezone()), "SHORT_DATE_FORMAT")
date_to = datetime(timezone.now().year, 8, 1)
date_to = formats.date_format(date_to, "SHORT_DATE_FORMAT")
params = {
Expand Down Expand Up @@ -798,7 +807,7 @@ def get_queryset(self):
q = (
Interview.objects.filter(applicant__campaign__branch__in=branches)
.select_related("applicant__campaign__branch", "venue__city")
.prefetch_related("interviewers")
.prefetch_related("interviewers", "slot__stream")
.annotate(average=Coalesce(Avg("comments__score"), Value(0.0)))
.order_by("date", "pk")
)
Expand Down Expand Up @@ -886,6 +895,7 @@ def get_context_data(self, **kwargs):
Prefetch(
"comments", queryset=(Comment.objects.select_related("interviewer"))
),
"slot__stream"
)
interview = get_object_or_404(qs)
context = get_applicant_context(self.request, interview.applicant_id)
Expand Down
28 changes: 14 additions & 14 deletions lms/jinja2/lms/admission/interview_invitation_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
<thead>
<tr>
<th>Поступающий</th>
<th>Секция</th>
<th>Дата</th>
<th>Время</th>
<th>Собеседующие</th>
<th style="width: 60px;">Статус</th>
<th style="width: 15%;">Секция</th>
<th style="width: 12%;">Дата</th>
<th style="width: 8%;">Время</th>
<th style="width: 18%;">Собеседующие</th>
<th style="width: 10%;">Статус</th>
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -64,11 +64,11 @@
<img data-toggle="tooltip" data-placement="top" title="{{ interviewer.full_name }}"
alt="{{ interviewer.full_name }}" src="{{ interviewer.photo }}" width="40" />
</a>
{{ interviewer.last_name }}
{% else %}
<div class="square" data-toggle="tooltip" data-placement="top" title="{{ interviewer.full_name }}">
{{ interviewer.full_name|slice(":1") }}</div>
{% endif %}
{{ interviewer.last_name }}
</a>
</li>
{% endfor %}
Expand All @@ -85,12 +85,12 @@
<table class="table">
<thead>
<tr>
<th>Поток</th>
<th>Секция</th>
<th>Формат</th>
<th>Слоты</th>
<th>Пригл. без&nbsp;ответа</th>
<th>Собеседующие</th>
<th style="width: 15%;">Поток</th>
<th style="width: 15%;">Секция</th>
<th style="width: 15%;">Формат</th>
<th style="width: 12%;">Слоты</th>
<th style="width: 20%;">Пригл. без&nbsp;ответа</th>
<th style="width: 23%;">Собеседующие</th>
</tr>
</thead>
<tbody>
Expand All @@ -113,14 +113,14 @@
<a target="_blank" href="{{ interviewer.get_absolute_url() }}">
<img data-toggle="tooltip" data-placement="top" title="{{ interviewer.get_full_name() }}"
alt="{{ interviewer.get_full_name() }}" src="{{ im.url }}" width="40" /></a>
{{ interviewer.last_name }}

{% else %}
<div class="square" data-toggle="tooltip" data-placement="top" title="{{ interviewer.get_full_name() }}">
{{ interviewer.get_full_name()|slice(":1") }}
</div>
{{ interviewer.last_name }}
{% endif %}
{% endwith -%}
{{ interviewer.last_name }}
</li>
{% endfor %}
</ul>
Expand Down
12 changes: 6 additions & 6 deletions lms/jinja2/lms/admission/send_interview_invitations.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ <h3 class="panel-title">Ожидают приглашения / {{ paginator.cou
<table class="table">
<thead>
<tr>
<th></th>
<th>Поступающий</th>
<th style="width: 30px;">Проп.</th>
<th style="width: 4%;"></th>
<th style="width: 15%;">Поступающий</th>
<th style="width: 7%;">Проп.</th>
<th>Заметка</th>
<th>Формат</th>
<th style="width: 60px;">Тест</th>
<th style="width: 60px;">Экз.</th>
<th style="width: 8%;">Формат</th>
<th style="width: 6%;">Тест</th>
<th style="width: 6%;">Экз.</th>
</tr>
</thead>
<tbody id="check-student">
Expand Down

0 comments on commit 363aa26

Please sign in to comment.