Skip to content

Commit

Permalink
RecruitmentForRecruiterSerializer and recruitment_progress (#1214)
Browse files Browse the repository at this point in the history
* add recruitmentforrecruiterserializer

* add tests for recruitment progress

* fix: merge

* feat: fix rename

---------

Co-authored-by: magsyg <[email protected]>
  • Loading branch information
magsyg and magsyg authored Sep 5, 2024
1 parent 089f2cf commit c7468ab
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 0 deletions.
2 changes: 2 additions & 0 deletions backend/root/utils/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@
samfundet__recruitment_list = 'samfundet:recruitment-list'
samfundet__recruitment_detail = 'samfundet:recruitment-detail'
samfundet__recruitment_gangs = 'samfundet:recruitment-gangs'
samfundet__recruitment_for_recruiter_list = 'samfundet:recruitment_for_recruiter-list'
samfundet__recruitment_for_recruiter_detail = 'samfundet:recruitment_for_recruiter-detail'
samfundet__recruitment_stats_list = 'samfundet:recruitment_stats-list'
samfundet__recruitment_stats_detail = 'samfundet:recruitment_stats-detail'
samfundet__recruitment_position_list = 'samfundet:recruitment_position-list'
Expand Down
6 changes: 6 additions & 0 deletions backend/samfundet/models/recruitment.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class Recruitment(CustomBaseModel):

max_applications = models.PositiveIntegerField(null=True, blank=True, verbose_name='Max applications per applicant')

def recruitment_progress(self) -> float:
applications = RecruitmentApplication.objects.filter(recruitment=self)
if applications.count() == 0:
return 1
return applications.exclude(recruiter_status=RecruitmentStatusChoices.NOT_SET).count() / applications.count()

def is_active(self) -> bool:
return self.visible_from < timezone.now() < self.actual_application_deadline

Expand Down
38 changes: 38 additions & 0 deletions backend/samfundet/models/tests/test_recruitment.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,3 +796,41 @@ def test_auto_newest_lowest_pri(self, fixture_recruitment_application: Recruitme
user=fixture_recruitment_application.user,
)
assert new_application.applicant_priority == 2

def test_recruitment_progress_no_applications(self, fixture_recruitment: Recruitment):
assert RecruitmentApplication.objects.filter(recruitment=fixture_recruitment).count() == 0
assert fixture_recruitment.recruitment_progress() == 1

def test_recruitment_progress_application_no_progress(self, fixture_recruitment: Recruitment, fixture_recruitment_application: RecruitmentApplication):
assert RecruitmentApplication.objects.filter(recruitment=fixture_recruitment).count() == 1
assert fixture_recruitment.recruitment_progress() == 0

def test_recruitment_progress_application_complete_progress(
self, fixture_recruitment: Recruitment, fixture_recruitment_application: RecruitmentApplication
):
assert RecruitmentApplication.objects.filter(recruitment=fixture_recruitment).count() == 1
assert fixture_recruitment.recruitment_progress() == 0
fixture_recruitment_application.recruiter_status = RecruitmentStatusChoices.CALLED_AND_ACCEPTED
fixture_recruitment_application.save()
assert fixture_recruitment.recruitment_progress() == 1

def test_recruitment_progress_applications_multiple_new_updates_progress(
self, fixture_recruitment: Recruitment, fixture_recruitment_application: RecruitmentApplication, fixture_user2: User
):
assert RecruitmentApplication.objects.filter(recruitment=fixture_recruitment).count() == 1
assert fixture_recruitment.recruitment_progress() == 0
fixture_recruitment_application.recruiter_status = RecruitmentStatusChoices.CALLED_AND_ACCEPTED
fixture_recruitment_application.save()
assert fixture_recruitment.recruitment_progress() == 1

new_application = RecruitmentApplication.objects.create(
application_text='Test application text 2',
recruitment_position=fixture_recruitment_application.recruitment_position,
recruitment=fixture_recruitment_application.recruitment,
user=fixture_user2,
)
assert fixture_recruitment.recruitment_progress() != 1

new_application.recruiter_status = RecruitmentStatusChoices.CALLED_AND_ACCEPTED
new_application.save()
assert fixture_recruitment.recruitment_progress() == 1
13 changes: 13 additions & 0 deletions backend/samfundet/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,19 @@ class Meta:
fields = '__all__'


class RecruitmentForRecruiterSerializer(CustomBaseSerializer):
seperate_positions = RecruitmentSeparatePositionSerializer(many=True, read_only=True)
recruitment_progress = serializers.SerializerMethodField(method_name='get_recruitment_progress', read_only=True)
statistics = RecruitmentStatisticsSerializer(read_only=True)

class Meta:
model = Recruitment
fields = '__all__'

def get_recruitment_progress(self, instance: Recruitment) -> float:
return instance.recruitment_progress()


class RecruitmentPositionSerializer(CustomBaseSerializer):
total_applicants = serializers.SerializerMethodField(method_name='get_total_applicants', read_only=True)
processed_applicants = serializers.SerializerMethodField(method_name='get_processed_applicants', read_only=True)
Expand Down
1 change: 1 addition & 0 deletions backend/samfundet/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

########## Recruitment ##########
router.register('recruitment', views.RecruitmentView, 'recruitment')
router.register('recruitment-for-recruiter', views.RecruitmentForRecruiterView, 'recruitment_for_recruiter')
router.register('recruitment-stats', views.RecruitmentStatisticsView, 'recruitment_stats')
router.register('recruitment-position', views.RecruitmentPositionView, 'recruitment_position')
router.register('recruitment-position-for-applicant', views.RecruitmentPositionForApplicantView, 'recruitment_position_for_applicant')
Expand Down
8 changes: 8 additions & 0 deletions backend/samfundet/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
UserForRecruitmentSerializer,
RecruitmentPositionSerializer,
RecruitmentStatisticsSerializer,
RecruitmentForRecruiterSerializer,
RecruitmentApplicationForGangSerializer,
RecruitmentUpdateUserPrioritySerializer,
RecruitmentPositionForApplicantSerializer,
Expand Down Expand Up @@ -604,6 +605,13 @@ def gangs(self, request: Request, **kwargs: Any) -> Response:
return Response(serializer.data)


@method_decorator(ensure_csrf_cookie, 'dispatch')
class RecruitmentForRecruiterView(ModelViewSet):
permission_classes = (DjangoModelPermissionsOrAnonReadOnly,)
serializer_class = RecruitmentForRecruiterSerializer
queryset = Recruitment.objects.all()


@method_decorator(ensure_csrf_cookie, 'dispatch')
class RecruitmentStatisticsView(ModelViewSet):
permission_classes = (DjangoModelPermissions,) # Allow read only to permissions on perms
Expand Down
1 change: 1 addition & 0 deletions frontend/src/dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ export type RecruitmentDto = {
max_applications?: number;
organization: number;
separate_positions?: RecruitmentSeparatePositionDto[];
recruitment_progress?: number;
};

export type RecruitmentSeparatePositionDto = {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/routes/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ export const ROUTES_BACKEND = {
samfundet__recruitment_list: '/api/recruitment/',
samfundet__recruitment_detail: '/api/recruitment/:pk/',
samfundet__recruitment_gangs: '/api/recruitment/:pk/gangs/',
samfundet__recruitment_for_recruiter_list: '/api/recruitment-for-recruiter/',
samfundet__recruitment_for_recruiter_detail: '/api/recruitment-for-recruiter/:pk/',
samfundet__recruitment_stats_list: '/api/recruitment-stats/',
samfundet__recruitment_stats_detail: '/api/recruitment-stats/:pk/',
samfundet__recruitment_position_list: '/api/recruitment-position/',
Expand Down

0 comments on commit c7468ab

Please sign in to comment.