Skip to content

Commit

Permalink
add per-year application report (#833)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmi4er4 authored Apr 16, 2024
1 parent 2d53e74 commit 17dbaf3
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 44 deletions.
102 changes: 69 additions & 33 deletions apps/admission/reports.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import datetime
from abc import abstractmethod
from typing import Callable

from django.db import models
from pandas import DataFrame

from django.db.models import Prefetch
Expand All @@ -14,55 +16,40 @@


class AdmissionApplicantsReport(ReportFileOutput):
def __init__(self, campaign):
exclude_applicant_fields = set()

def __init__(self):
super().__init__()
self.campaign = campaign
self.process()

@abstractmethod
def get_queryset(self):
return (
Applicant.objects.filter(campaign=self.campaign.pk)
.select_related("exam", "online_test")
.prefetch_related(
"university_legacy",
Prefetch(
"interviews",
queryset=(
Interview.objects.prefetch_related(
Prefetch(
"comments",
queryset=(
Comment.objects.select_related("interviewer")
),
)
)
),
),
)
.order_by("pk")
)
raise NotImplementedError()

def process(self):
applicants = (self.get_queryset()
.defer(*self.exclude_applicant_fields)
.select_related("exam", "online_test")
)
self.exclude_applicant_fields.update(("modified", "meta"))
# Collect headers
exclude_applicant_fields = {
"modified",
"uuid",
"yandex_login_q",
"campaign",
"user",
"meta",
}
applicant_fields = [
f for f in Applicant._meta.fields if f.name not in exclude_applicant_fields
f for f in Applicant._meta.fields if f.name not in self.exclude_applicant_fields
]

to_prefetch = [field.name for field in applicant_fields if isinstance(field, models.ForeignKey)]
if "campaign" in to_prefetch:
to_prefetch.append("campaign__branch")

applicants = applicants.prefetch_related(*to_prefetch)

self.headers = [force_str(f.verbose_name) for f in applicant_fields]
self.headers.extend(
[
"Результаты теста",
"Результаты экзамена",
]
)
applicants = self.get_queryset()
# Collect data
for applicant in applicants:
row = []
Expand Down Expand Up @@ -96,6 +83,19 @@ def process(self):
def export_row(self, row):
return row

class AdmissionApplicantsCampaignReport(AdmissionApplicantsReport):
exclude_applicant_fields = {
"yandex_login_q",
"campaign",
"user",
}
def __init__(self, campaign):
self.campaign = campaign
super().__init__()

def get_queryset(self):
return Applicant.objects.filter(campaign=self.campaign.pk).order_by("pk")

def get_filename(self):
today = datetime.datetime.now()
return "admission_{}_{}_report_{}".format(
Expand All @@ -105,6 +105,42 @@ def get_filename(self):
)


class AdmissionApplicantsYearReport(AdmissionApplicantsReport):
exclude_applicant_fields = {
"user",
"yandex_login_q",
"photo",
"telegram_username",
"is_unsubscribed",
"stepic_id",
"github_login",
"graduate_work",
"online_education_experience",
"experience",
"internship_beginning",
"internship_end",
"working_hours",
"probability",
"preferred_study_programs",
"preferred_study_program_notes",
"preferred_study_programs_dm_note",
"preferred_study_programs_se_note",
"preferred_study_programs_cs_note",
"your_future_plans",
"admin_note",
}

def __init__(self, year):
self.year = year
super().__init__()

def get_queryset(self):
return Applicant.objects.filter(campaign__year=self.year).exclude(campaign__branch__name='Тест').order_by("pk")

def get_filename(self):
today = datetime.datetime.now()
return f"admission_{self.year}_report_{formats.date_format(today, 'SHORT_DATE_FORMAT')}"

class AdmissionExamReport:
def __init__(self, campaign):
self.campaign = campaign
Expand Down
4 changes: 2 additions & 2 deletions apps/admission/tests/test_reports.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

from admission.constants import InterviewSections
from admission.reports import AdmissionApplicantsReport, AdmissionExamReport
from admission.reports import AdmissionApplicantsCampaignReport, AdmissionExamReport
from admission.tests.factories import (
ApplicantFactory,
CampaignFactory,
Expand Down Expand Up @@ -32,7 +32,7 @@ def test_report_smoke():
applicant=applicant, section=InterviewSections.ALL_IN_ONE
)
CommentFactory(score=1, interview=interview)
report = AdmissionApplicantsReport(campaign=campaign)
report = AdmissionApplicantsCampaignReport(campaign=campaign)
assert len(report.data) == 1


Expand Down
19 changes: 17 additions & 2 deletions apps/staff/templates/staff/exports.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ <h2>Набор</h2>
<tr>
<td>{{ campaign }}</td>
<td>
<a target="_blank" href="{% url 'staff:exports_report_admission_applicants' campaign.pk 'csv' %}">csv</a>,
<a target="_blank" href="{% url 'staff:exports_report_admission_applicants' campaign.pk 'xlsx' %}">xlsx</a>
<a target="_blank" href="{% url 'staff:exports_report_admission_campaign_applicants' campaign.pk 'csv' %}">csv</a>,
<a target="_blank" href="{% url 'staff:exports_report_admission_campaign_applicants' campaign.pk 'xlsx' %}">xlsx</a>
</td>
<td>
<a target="_blank" href="{% url 'staff:exports_report_admission_exam' campaign.pk 'csv' %}">csv</a>,
Expand All @@ -140,6 +140,21 @@ <h2>Набор</h2>
</tr>
{% endfor %}

<table class="table table-bordered bg-white">
<tr>
<th>Год набора</th>
<th>Анкеты</th>
</tr>
{% for year in years %}
<tr>
<td>{{ year }}</td>
<td>
<a target="_blank" href="{% url 'staff:exports_report_admission_year_applicants' year 'csv' %}">csv</a>,
<a target="_blank" href="{% url 'staff:exports_report_admission_year_applicants' year 'xlsx' %}">xlsx</a>
</td>
</tr>
{% endfor %}

</table>
</div>
</div>
Expand Down
9 changes: 6 additions & 3 deletions apps/staff/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
)
from staff.api.views import CreateAlumniProfiles, StudentSearchJSONView
from staff.views import (
AdmissionApplicantsReportView, AdmissionExamReportView,
AdmissionApplicantsCampaignReportView, AdmissionExamReportView,
AdmissionInterviewsReportView, CourseParticipantsIntersectionView,
EnrollmentInvitationListView, ExportsView, FutureGraduateDiplomasCSVView,
FutureGraduateDiplomasTeXView, FutureGraduateStatsView, GradeBookListView,
HintListView, InterviewerFacesView, InvitationStudentsProgressReportView,
OfficialDiplomasCSVView, OfficialDiplomasListView, OfficialDiplomasTeXView,
ProgressReportForSemesterView, ProgressReportFullView, StudentFacesView,
StudentSearchCSVView, StudentSearchView, SurveySubmissionsReportView,
SurveySubmissionsStatsView, WillGraduateStatsReportView
SurveySubmissionsStatsView, WillGraduateStatsReportView, AdmissionApplicantsYearReportView
)

from staff.views import autograde_projects, autofail_ungraded, create_alumni_profiles
Expand Down Expand Up @@ -91,7 +91,10 @@ def to_url(self, value):
path('tex/', OfficialDiplomasTeXView.as_view(), name='exports_official_diplomas_tex'),
path('csv/', OfficialDiplomasCSVView.as_view(), name='exports_official_diplomas_csv'),
])),
path('reports/admission/<int:campaign_id>/applicants/<export_fmt:output_format>/', AdmissionApplicantsReportView.as_view(), name='exports_report_admission_applicants'),
path('reports/admission/<int:campaign_id>/campain_applicants/<export_fmt:output_format>/',
AdmissionApplicantsCampaignReportView.as_view(), name='exports_report_admission_campaign_applicants'),
path('reports/admission/<int:year>/year_applicants/<export_fmt:output_format>/',
AdmissionApplicantsYearReportView.as_view(), name='exports_report_admission_year_applicants'),
path('reports/admission/<int:campaign_id>/interviews/<export_fmt:output_format>/', AdmissionInterviewsReportView.as_view(), name='exports_report_admission_interviews'),
path('reports/admission/<int:campaign_id>/exam/<export_fmt:output_format>/', AdmissionExamReportView.as_view(), name='exports_report_admission_exam'),
re_path(r'^reports/surveys/(?P<survey_pk>\d+)/(?P<output_format>csv|xlsx)/$', SurveySubmissionsReportView.as_view(), name='exports_report_survey_submissions'),
Expand Down
22 changes: 18 additions & 4 deletions apps/staff/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
import core.utils
from admission.models import Campaign, Interview
from admission.reports import (
AdmissionApplicantsReport,
AdmissionApplicantsCampaignReport,
AdmissionExamReport,
generate_admission_interviews_report,
generate_admission_interviews_report, AdmissionApplicantsYearReport,
)
from core.http import HttpRequest
from core.models import Branch
from core.typings import assert_never
from core.urls import reverse
from core.utils import bucketize
from courses.constants import SemesterTypes
Expand Down Expand Up @@ -149,6 +150,7 @@ def get_context_data(self, **kwargs):
.select_related("branch")
.order_by("-year", "branch__name")
),
"years": range(2020, current_term.year + 1),
"branches": branches,
"official_diplomas_dates": official_diplomas_dates,
}
Expand Down Expand Up @@ -448,16 +450,28 @@ def get(self, request, output_format, invitation_id, *args, **kwargs):
return dataframe_to_response(report.generate(), output_format, file_name)


class AdmissionApplicantsReportView(CuratorOnlyMixin, generic.base.View):
class AdmissionApplicantsCampaignReportView(CuratorOnlyMixin, generic.base.View):
def get(self, request, campaign_id, output_format, **kwargs):
campaign = get_object_or_404(
Campaign.objects.filter(pk=campaign_id, branch__site_id=settings.SITE_ID)
)
report = AdmissionApplicantsReport(campaign=campaign)
report = AdmissionApplicantsCampaignReport(campaign=campaign)
if output_format == "csv":
return report.output_csv()
elif output_format == "xlsx":
return report.output_xlsx()
else:
assert_never(output_format)

class AdmissionApplicantsYearReportView(CuratorOnlyMixin, generic.base.View):
def get(self, request, output_format, year, **kwargs):
report = AdmissionApplicantsYearReport(year=year)
if output_format == "csv":
return report.output_csv()
elif output_format == "xlsx":
return report.output_xlsx()
else:
assert_never(output_format)


class AdmissionInterviewsReportView(CuratorOnlyMixin, generic.base.View):
Expand Down

0 comments on commit 17dbaf3

Please sign in to comment.