Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1535 bug withdrawn application showing up for applicant #1542

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9f4bfa1
Add withdraw to application overview
Mathias-a Oct 13, 2024
52308ba
add confirm
Mathias-a Oct 22, 2024
922162d
Merge branch '1484-add-ability-to-withdraw-to-recruitmentapplications…
Snorre98 Oct 23, 2024
7dfbf06
reafactor creating sub compontens
Snorre98 Oct 24, 2024
8f18de9
adds filter which fixes the bug in frontend. Should try ti implement …
Snorre98 Oct 24, 2024
d963df3
configurates views to fetch correct withdrwan or non-withdrawn applic…
Snorre98 Oct 24, 2024
6482d45
adds api call to get withdrawn applications
Snorre98 Oct 24, 2024
df9184c
implements withdrawn / ono-withdrawn api calls in components
Snorre98 Oct 24, 2024
8153eff
adds translations and changes styling
Snorre98 Oct 24, 2024
7702821
fixed translations and refactored table
Snorre98 Oct 24, 2024
275d758
implements react query
Snorre98 Oct 24, 2024
d96c59f
adds logic for rebasing application priority
Snorre98 Oct 24, 2024
c2159f7
adds priority direction indicator on positions
Snorre98 Nov 2, 2024
9f52e63
improved priority controll by adding buttons
Snorre98 Nov 2, 2024
5204851
small tweek to tyling of priority indicator, makes it larger and repo…
Snorre98 Nov 2, 2024
f64d843
small changes to translation
Snorre98 Nov 2, 2024
a171a39
small change to tranlsation
Snorre98 Nov 2, 2024
2775500
changed translation, hopfully the last time
Snorre98 Nov 2, 2024
db7bb36
moved the logic for handling the applicant position prioritization to…
Snorre98 Nov 2, 2024
4a267be
refactor recruitment application withdraw and prioritization validati…
Snorre98 Nov 2, 2024
c23f7dc
adds comments and doc strings
Snorre98 Nov 2, 2024
45387c3
adds comments to update application state methode
Snorre98 Nov 2, 2024
13ac009
validates application deadline
Snorre98 Nov 3, 2024
843a193
validates applicant priority deadline
Snorre98 Nov 3, 2024
725c38c
validates recruitment admin priority of applications
Snorre98 Nov 3, 2024
84c4b1f
Merge branch 'master' into 1535-bug-withdrawn-application-showing-up-…
Snorre98 Nov 3, 2024
3672d88
resolves migration file conflict, destructivly
Snorre98 Nov 3, 2024
5709118
fixed id error from after resolving merge conflict
Snorre98 Nov 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Generated by Django 5.1.1 on 2024-11-03 01:16

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('samfundet', '0010_recruitment_promo_media'),
]

operations = [
migrations.AlterField(
model_name='recruitmentapplication',
name='applicant_priority',
field=models.PositiveIntegerField(blank=True, help_text='Applicant priority of the position(recruitment_position) to which this application related.', null=True),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='applicant_state',
field=models.IntegerField(choices=[(0, 'Unprocessed by all above on priority'), (1, 'Highest priority, and reserve'), (2, 'Highest priority, and wanted'), (3, 'Another position has this on reserve, with higher priority'), (4, 'Another position has this on reserve, with higher priority, but you have reserved'), (5, 'Another position has this on reserve, with higher priority, but you have them as wanted'), (6, 'Another position has this on reserve, with higher priority'), (7, 'Another position has this on wanted, with higher priority, but you have reserved'), (8, 'Another position has this on wanted, with higher priority, but you have them as wanted'), (10, 'Other position has priority')], default=0, help_text="Recruiter's view of the applicant's status."),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='application_text',
field=models.TextField(help_text='Motivation text submitted by the applicant'),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='interview',
field=models.ForeignKey(blank=True, help_text='Interview associated with this application.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='samfundet.interview'),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='recruiter_priority',
field=models.IntegerField(choices=[(0, 'Not Set'), (1, 'Reserve'), (2, 'Wanted'), (3, 'Not Wanted')], default=0, help_text="Recruiter's priority for this application - should not be visible to applicant"),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='recruiter_status',
field=models.IntegerField(choices=[(0, 'Not Set'), (1, 'Called and Accepted'), (2, 'Called and Rejected'), (3, 'Rejection'), (4, 'Automatic Rejection')], default=0, help_text='Current status of this application.'),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='recruitment',
field=models.ForeignKey(help_text='Recruitment to which this application is related.', on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='samfundet.recruitment'),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='recruitment_position',
field=models.ForeignKey(help_text='Position to which this application is related.', on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='samfundet.recruitmentposition'),
),
migrations.AlterField(
model_name='recruitmentapplication',
name='user',
field=models.ForeignKey(help_text='User who submitted this application.', on_delete=django.db.models.deletion.CASCADE, related_name='applications', to=settings.AUTH_USER_MODEL),
),
]
435 changes: 339 additions & 96 deletions backend/samfundet/models/recruitment.py

Large diffs are not rendered by default.

128 changes: 128 additions & 0 deletions backend/samfundet/models/tests/test_recruitment.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,134 @@ def test_recruitment_progress_applications_multiple_new_updates_progress(
assert fixture_recruitment.recruitment_progress() == 1


@pytest.mark.django_db
def test_withdrawn_application_priority_handling(
fixture_recruitment_application: RecruitmentApplication,
fixture_recruitment_application2: RecruitmentApplication,
fixture_recruitment_position2: RecruitmentPosition,
):
"""Test that priorities are properly managed when applications are withdrawn"""
# Initial state - two applications with priorities 1 and 2
assert fixture_recruitment_application.applicant_priority == 1
assert fixture_recruitment_application2.applicant_priority == 2

# When withdrawing application 1, application 2 should become priority 1
fixture_recruitment_application.withdrawn = True
fixture_recruitment_application.save()

fixture_recruitment_application.refresh_from_db()
fixture_recruitment_application2.refresh_from_db()

assert fixture_recruitment_application.applicant_priority is None
assert fixture_recruitment_application2.applicant_priority == 1

# New application should get priority 2
new_application = RecruitmentApplication.objects.create(
application_text='Test application text 3',
recruitment_position=fixture_recruitment_position2,
recruitment=fixture_recruitment_position2.recruitment,
user=fixture_recruitment_application.user,
)

assert new_application.applicant_priority == 2


@pytest.mark.django_db
def test_reapplying_after_withdrawal_priority(
fixture_recruitment_application: RecruitmentApplication, fixture_recruitment_application2: RecruitmentApplication
):
"""Test that reapplying after withdrawal gets correct priority"""
# Initial state
assert fixture_recruitment_application.applicant_priority == 1
assert fixture_recruitment_application2.applicant_priority == 2

# Withdraw first application
fixture_recruitment_application.withdrawn = True
fixture_recruitment_application.save()

fixture_recruitment_application2.refresh_from_db()
assert fixture_recruitment_application2.applicant_priority == 1

# Reapply - should get priority 2
fixture_recruitment_application.withdrawn = False
fixture_recruitment_application.save()

fixture_recruitment_application.refresh_from_db()
fixture_recruitment_application2.refresh_from_db()

assert fixture_recruitment_application2.applicant_priority == 1
assert fixture_recruitment_application.applicant_priority == 2


@pytest.mark.django_db
def test_priority_constraints_with_withdrawn_applications(
fixture_recruitment_application: RecruitmentApplication,
fixture_recruitment_application2: RecruitmentApplication,
fixture_recruitment_position2: RecruitmentPosition,
):
"""Test that priorities stay within bounds of active applications only"""
# Initial state
assert fixture_recruitment_application.applicant_priority == 1
assert fixture_recruitment_application2.applicant_priority == 2

# Withdraw application 2
fixture_recruitment_application2.withdrawn = True
fixture_recruitment_application2.save()

fixture_recruitment_application.refresh_from_db()
assert fixture_recruitment_application.applicant_priority == 1

# Try to set priority higher than number of active applications
with pytest.raises(ValidationError):
fixture_recruitment_application.applicant_priority = 2
fixture_recruitment_application.save()


@pytest.mark.django_db
def test_multiple_withdrawals_and_priorities(
fixture_recruitment: Recruitment, fixture_recruitment_position: RecruitmentPosition, fixture_recruitment_position2: RecruitmentPosition, fixture_user: User
):
"""Test complex scenario with multiple withdrawals and reapplications"""
# Create three applications
apps = []
for i in range(3):
app = RecruitmentApplication.objects.create(
application_text=f'Test application {i}',
recruitment_position=fixture_recruitment_position if i < 2 else fixture_recruitment_position2,
recruitment=fixture_recruitment,
user=fixture_user,
)
apps.append(app)

# Verify initial priorities
for i, app in enumerate(apps, 1):
assert app.applicant_priority == i

# Withdraw middle application
apps[1].withdrawn = True
apps[1].save()

# Refresh and verify priorities adjusted
for app in apps:
app.refresh_from_db()

assert apps[0].applicant_priority == 1
assert apps[1].applicant_priority is None
assert apps[2].applicant_priority == 2

# Withdraw first application
apps[0].withdrawn = True
apps[0].save()

# Refresh and verify
for app in apps:
app.refresh_from_db()

assert apps[0].applicant_priority is None
assert apps[1].applicant_priority is None
assert apps[2].applicant_priority == 1


def test_position_must_have_single_owner(fixture_recruitment_position: RecruitmentPosition, fixture_gang: Gang, fixture_gang_section: GangSection):
fixture_recruitment_position.gang = fixture_gang
fixture_recruitment_position.section = fixture_gang_section
Expand Down
Loading