first refactoring in the ai_overview branch for the candidate to application for views and urls name

This commit is contained in:
Faheed 2025-11-26 12:59:59 +03:00
parent 473dc8e00f
commit 1ad85b82e1
57 changed files with 394 additions and 393 deletions

View File

@ -26,7 +26,7 @@ urlpatterns = [
path('application/<slug:template_slug>/', views.application_submit_form, name='application_submit_form'),
path('application/<slug:template_slug>/submit/', views.application_submit, name='application_submit'),
path('application/<slug:slug>/apply/', views.application_detail, name='application_detail'),
path('application/<slug:slug>/signup/', views.candidate_signup, name='candidate_signup'),
path('application/<slug:slug>/signup/', views.application_signup, name='application_signup'),
path('application/<slug:slug>/success/', views.application_success, name='application_success'),
# path('application/applicant/profile', views.applicant_profile, name='applicant_profile'),

View File

@ -79,10 +79,10 @@ def debug_url_routing():
print(f"Error with document_upload URL: {e}")
try:
url2 = reverse('candidate_document_upload', kwargs={'slug': application.slug})
print(f"URL pattern 2 (candidate_document_upload): {url2}")
url2 = reverse('pplication_document_upload', kwargs={'slug': application.slug})
print(f"URL pattern 2 (pplication_document_upload): {url2}")
except Exception as e:
print(f"Error with candidate_document_upload URL: {e}")
print(f"Error with pplication_document_upload URL: {e}")
# Test GET request to see if the URL is accessible
try:

View File

@ -24,7 +24,7 @@ class CustomAuthenticationBackend(AuthenticationBackend):
elif user.user_type == 'agency':
redirect_url = reverse('agency_portal_dashboard')
elif user.user_type == 'candidate':
redirect_url = reverse('candidate_portal_dashboard')
redirect_url = reverse('applicant_portal_dashboard')
else:
# Fallback to default redirect URL if user type is unknown
redirect_url = '/'

View File

@ -55,7 +55,7 @@ def user_type_required(allowed_types=None, login_url=None):
if user.user_type == 'agency':
return redirect('agency_portal_dashboard')
elif user.user_type == 'candidate':
return redirect('candidate_portal_dashboard')
return redirect('applicant_portal_dashboard')
else:
return redirect('dashboard')
@ -92,7 +92,7 @@ class UserTypeRequiredMixin(AccessMixin):
if request.user.user_type == 'agency':
return redirect('agency_portal_dashboard')
elif request.user.user_type == 'candidate':
return redirect('candidate_portal_dashboard')
return redirect('applicant_portal_dashboard')
else:
return redirect('dashboard')

View File

@ -2344,7 +2344,7 @@ class MessageForm(forms.ModelForm):
)
class CandidateSignupForm(forms.ModelForm):
class ApplicantSignupForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))
confirm_password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))

View File

@ -19,8 +19,8 @@ from .forms import (
CandidateStageForm, InterviewScheduleForm, CandidateSignupForm
)
from .views import (
ZoomMeetingListView, ZoomMeetingCreateView, job_detail, candidate_screening_view,
candidate_exam_view, candidate_interview_view, api_schedule_candidate_meeting
ZoomMeetingListView, ZoomMeetingCreateView, job_detail, applications_screening_view,
applications_exam_view, applications_interview_view, api_schedule_application_meeting
)
from .views_frontend import CandidateListView, JobListView
from .utils import create_zoom_meeting, get_candidates_from_request
@ -189,32 +189,32 @@ class ViewTests(BaseTestCase):
def test_candidate_screening_view(self):
"""Test candidate_screening_view"""
response = self.client.get(reverse('candidate_screening_view', kwargs={'slug': self.job.slug}))
response = self.client.get(reverse('applications_screening_view', kwargs={'slug': self.job.slug}))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'John Doe')
def test_candidate_screening_view_filters(self):
"""Test candidate_screening_view with filters"""
response = self.client.get(
reverse('candidate_screening_view', kwargs={'slug': self.job.slug}),
reverse('applications_screening_view', kwargs={'slug': self.job.slug}),
{'min_ai_score': '50', 'tier1_count': '5'}
)
self.assertEqual(response.status_code, 200)
def test_candidate_exam_view(self):
"""Test candidate_exam_view"""
response = self.client.get(reverse('candidate_exam_view', kwargs={'slug': self.job.slug}))
response = self.client.get(reverse('applications_exam_view', kwargs={'slug': self.job.slug}))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'John Doe')
def test_candidate_interview_view(self):
"""Test candidate_interview_view"""
response = self.client.get(reverse('candidate_interview_view', kwargs={'slug': self.job.slug}))
"""Test applications_interview_view"""
response = self.client.get(reverse('applications_interview_view', kwargs={'slug': self.job.slug}))
self.assertEqual(response.status_code, 200)
@patch('recruitment.views.create_zoom_meeting')
def test_schedule_candidate_meeting(self, mock_create_zoom):
"""Test api_schedule_candidate_meeting view"""
"""Test api_schedule_application_meeting view"""
mock_create_zoom.return_value = {
'status': 'success',
'meeting_details': {
@ -231,7 +231,7 @@ class ViewTests(BaseTestCase):
'duration': 60
}
response = self.client.post(
reverse('api_schedule_candidate_meeting',
reverse('api_schedule_application_meeting',
kwargs={'job_slug': self.job.slug, 'candidate_pk': self.candidate.pk}),
data
)
@ -478,7 +478,7 @@ class PerformanceTests(BaseTestCase):
)
# Test pagination
response = self.client.get(reverse('candidate_list'))
response = self.client.get(reverse('application_list'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Candidate')

View File

@ -33,8 +33,8 @@ from .forms import (
ApplicationStageForm, InterviewScheduleForm, BreakTimeFormSet
)
from .views import (
ZoomMeetingListView, ZoomMeetingCreateView, job_detail, candidate_screening_view,
candidate_exam_view, candidate_interview_view, api_schedule_candidate_meeting,
ZoomMeetingListView, ZoomMeetingCreateView, job_detail, applications_screening_view,
applications_exam_view, applications_interview_view, api_schedule_application_meeting,
schedule_interviews_view, confirm_schedule_interviews_view, _handle_preview_submission,
_handle_confirm_schedule, _handle_get_request
)
@ -421,27 +421,27 @@ class AdvancedViewTests(TestCase):
)
# Test search by name
response = self.client.get(reverse('candidate_list'), {
response = self.client.get(reverse('application_list'), {
'search': 'Jane'
})
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Jane Smith')
# Test search by email
response = self.client.get(reverse('candidate_list'), {
response = self.client.get(reverse('application_list'), {
'search': 'bob@example.com'
})
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Bob Johnson')
# Test filter by job
response = self.client.get(reverse('candidate_list'), {
response = self.client.get(reverse('application_list'), {
'job': self.job.slug
})
self.assertEqual(response.status_code, 200)
# Test filter by stage
response = self.client.get(reverse('candidate_list'), {
response = self.client.get(reverse('application_list'), {
'stage': 'Exam'
})
self.assertEqual(response.status_code, 200)
@ -521,7 +521,7 @@ class AdvancedViewTests(TestCase):
"""Test HTMX responses for partial updates"""
# Test HTMX request for candidate screening
response = self.client.get(
reverse('candidate_screening_view', kwargs={'slug': self.job.slug}),
reverse('applications_screening_view', kwargs={'slug': self.job.slug}),
HTTP_HX_REQUEST='true'
)
self.assertEqual(response.status_code, 200)
@ -557,7 +557,7 @@ class AdvancedViewTests(TestCase):
# This would be tested via a form submission
# For now, we test the view logic directly
request = self.client.post(
reverse('candidate_update_status', kwargs={'slug': self.job.slug}),
reverse('application_update_status', kwargs={'slug': self.job.slug}),
data={'candidate_ids': application_ids, 'mark_as': 'Exam'}
)
# Should redirect back to the view
@ -954,7 +954,7 @@ class AdvancedIntegrationTests(TransactionTestCase):
)
response = self.client.post(
reverse('api_schedule_candidate_meeting',
reverse('api_schedule_application_meeting',
kwargs={'job_slug': job.slug, 'candidate_pk': application.pk}),
data={
'start_time': (timezone.now() + timedelta(hours=1)).isoformat(),

View File

@ -41,52 +41,52 @@ urlpatterns = [
# Candidate URLs
path(
"candidates/", views_frontend.ApplicationListView.as_view(), name="candidate_list"
"applications/", views_frontend.ApplicationListView.as_view(), name="application_list"
),
path(
"candidates/create/",
"application/create/",
views_frontend.ApplicationCreateView.as_view(),
name="candidate_create",
name="application_create",
),
path(
"candidates/create/<slug:slug>/",
"application/create/<slug:slug>/",
views_frontend.ApplicationCreateView.as_view(),
name="candidate_create_for_job",
name="application_create_for_job",
),
path(
"jobs/<slug:slug>/candidates/",
"jobs/<slug:slug>/application/",
views_frontend.JobApplicationListView.as_view(),
name="job_candidates_list",
name="job_applications_list",
),
path(
"candidates/<slug:slug>/update/",
"applications/<slug:slug>/update/",
views_frontend.ApplicationUpdateView.as_view(),
name="candidate_update",
name="application_update",
),
path(
"candidates/<slug:slug>/delete/",
"application/<slug:slug>/delete/",
views_frontend.ApplicationDeleteView.as_view(),
name="candidate_delete",
name="application_delete",
),
path(
"candidate/<slug:slug>/view/",
views_frontend.candidate_detail,
name="candidate_detail",
"application/<slug:slug>/view/",
views_frontend.application_detail,
name="application_detail",
),
path(
"candidate/<slug:slug>/resume-template/",
views_frontend.candidate_resume_template_view,
name="candidate_resume_template",
"application/<slug:slug>/resume-template/",
views_frontend.application_resume_template_view,
name="application_resume_template",
),
path(
"candidate/<slug:slug>/update-stage/",
views_frontend.candidate_update_stage,
name="candidate_update_stage",
"application/<slug:slug>/update-stage/",
views_frontend.application_update_stage,
name="application_update_stage",
),
path(
"candidate/<slug:slug>/retry-scoring/",
"application/<slug:slug>/retry-scoring/",
views_frontend.retry_scoring_view,
name="candidate_retry_scoring",
name="application_retry_scoring",
),
# Training URLs
path("training/", views_frontend.TrainingListView.as_view(), name="training_list"),
@ -155,50 +155,50 @@ urlpatterns = [
name="edit_linkedin_post_content",
),
path(
"jobs/<slug:slug>/candidate_screening_view/",
views.candidate_screening_view,
name="candidate_screening_view",
"jobs/<slug:slug>/applications_screening_view/",
views.applications_screening_view,
name="applications_screening_view",
),
path(
"jobs/<slug:slug>/candidate_exam_view/",
views.candidate_exam_view,
name="candidate_exam_view",
"jobs/<slug:slug>/applications_exam_view/",
views.applications_exam_view,
name="applications_exam_view",
),
path(
"jobs/<slug:slug>/candidate_interview_view/",
views.candidate_interview_view,
name="candidate_interview_view",
"jobs/<slug:slug>/applications_interview_view/",
views.applications_interview_view,
name="applications_interview_view",
),
path(
"jobs/<slug:slug>/candidate_document_review_view/",
views.candidate_document_review_view,
name="candidate_document_review_view",
"jobs/<slug:slug>/applications_document_review_view/",
views.applications_document_review_view,
name="applications_document_review_view",
),
path(
"jobs/<slug:slug>/candidate_offer_view/",
views_frontend.candidate_offer_view,
name="candidate_offer_view",
"jobs/<slug:slug>/applications_offer_view/",
views_frontend.applications_offer_view,
name="applications_offer_view",
),
path(
"jobs/<slug:slug>/candidate_hired_view/",
views_frontend.candidate_hired_view,
name="candidate_hired_view",
"jobs/<slug:slug>/applications_hired_view/",
views_frontend.applications_hired_view,
name="applications_hired_view",
),
path(
"jobs/<slug:job_slug>/export/<str:stage>/csv/",
views_frontend.export_candidates_csv,
name="export_candidates_csv",
views_frontend.export_applications_csv,
name="export_applications_csv",
),
path(
"jobs/<slug:job_slug>/candidates/<slug:candidate_slug>/update_status/<str:stage_type>/<str:status>/",
views_frontend.update_candidate_status,
name="update_candidate_status",
"jobs/<slug:job_slug>/application/<slug:application_slug>/update_status/<str:stage_type>/<str:status>/",
views_frontend.update_application_status,
name="update_application_status",
),
# Sync URLs
path(
"jobs/<slug:job_slug>/sync-hired-candidates/",
views_frontend.sync_hired_candidates,
name="sync_hired_candidates",
"jobs/<slug:job_slug>/sync-hired-applications/",
views_frontend.sync_hired_applications,
name="sync_hired_applications",
),
path(
"sources/<int:source_id>/test-connection/",
@ -206,34 +206,34 @@ urlpatterns = [
name="test_source_connection",
),
path(
"jobs/<slug:slug>/<int:candidate_id>/reschedule_meeting_for_candidate/<int:meeting_id>/",
views.reschedule_meeting_for_candidate,
name="reschedule_meeting_for_candidate",
"jobs/<slug:slug>/<int:application_id>/reschedule_meeting_for_application/<int:meeting_id>/",
views.reschedule_meeting_for_application,
name="reschedule_meeting_for_application",
),
path(
"jobs/<slug:slug>/update_candidate_exam_status/",
views.update_candidate_exam_status,
name="update_candidate_exam_status",
"jobs/<slug:slug>/update_application_exam_status/",
views.update_application_exam_status,
name="update_application_exam_status",
),
path(
"jobs/<slug:slug>/bulk_update_candidate_exam_status/",
views.bulk_update_candidate_exam_status,
name="bulk_update_candidate_exam_status",
"jobs/<slug:slug>/bulk_update_application_exam_status/",
views.bulk_update_application_exam_status,
name="bulk_update_application_exam_status",
),
path(
"htmx/<int:pk>/candidate_criteria_view/",
views.candidate_criteria_view_htmx,
name="candidate_criteria_view_htmx",
"htmx/<int:pk>/application_criteria_view/",
views.application_criteria_view_htmx,
name="application_criteria_view_htmx",
),
path(
"htmx/<slug:slug>/candidate_set_exam_date/",
views.candidate_set_exam_date,
name="candidate_set_exam_date",
"htmx/<slug:slug>/application_set_exam_date/",
views.application_set_exam_date,
name="application_set_exam_date",
),
path(
"htmx/<slug:slug>/candidate_update_status/",
views.candidate_update_status,
name="candidate_update_status",
"htmx/<slug:slug>/application_update_status/",
views.application_update_status,
name="application_update_status",
),
# path('forms/form/<slug:template_slug>/submit/', views.submit_form, name='submit_form'),
# path('forms/form/<slug:template_slug>/', views.form_wizard_view, name='form_wizard'),
@ -347,9 +347,9 @@ urlpatterns = [
name="delete_meeting_comment",
),
path(
"meetings/<slug:slug>/set_meeting_candidate/",
views.set_meeting_candidate,
name="set_meeting_candidate",
"meetings/<slug:slug>/set_meeting_application/",
views.set_meeting_application,
name="set_meeting_application",
),
# Hiring Agency URLs
path("agencies/", views.agency_list, name="agency_list"),
@ -358,9 +358,9 @@ urlpatterns = [
path("agencies/<slug:slug>/update/", views.agency_update, name="agency_update"),
path("agencies/<slug:slug>/delete/", views.agency_delete, name="agency_delete"),
path(
"agencies/<slug:slug>/candidates/",
views.agency_candidates,
name="agency_candidates",
"agencies/<slug:slug>/applications/",
views.agency_applications,
name="agency_applications",
),
# path('agencies/<slug:slug>/send-message/', views.agency_detail_send_message, name='agency_detail_send_message'),
# Agency Assignment Management URLs
@ -433,19 +433,19 @@ urlpatterns = [
# Unified Portal URLs
path("login/", views.portal_login, name="portal_login"),
path(
"candidate/dashboard/",
views.candidate_portal_dashboard,
name="candidate_portal_dashboard",
"applicant/dashboard/",
views.applicant_portal_dashboard,
name="applicant_portal_dashboard",
),
path(
"candidate/applications/<slug:slug>/",
views.candidate_application_detail,
name="candidate_application_detail",
"applications/applications/<slug:slug>/",
views.applicant_application_detail,
name="applicant_application_detail",
),
# path(
# "candidate/<slug:application_slug>/applications/<slug:person_slug>/detail/<slug:agency_slug>/",
# views.candidate_application_detail,
# name="candidate_application_detail",
# views.applicant_application_detail,
# name="applicant_application_detail",
# ),
path(
"portal/dashboard/",
@ -463,35 +463,35 @@ urlpatterns = [
name="agency_portal_assignment_detail",
),
path(
"portal/assignment/<slug:slug>/submit-candidate/",
views.agency_portal_submit_candidate_page,
name="agency_portal_submit_candidate_page",
"portal/assignment/<slug:slug>/submit-application/",
views.agency_portal_submit_application_page,
name="agency_portal_submit_application_page",
),
path(
"portal/submit-candidate/",
views.agency_portal_submit_candidate,
name="agency_portal_submit_candidate",
"portal/submit-application/",
views.agency_portal_submit_application,
name="agency_portal_submit_application",
),
path("portal/logout/", views.portal_logout, name="portal_logout"),
# Agency Portal Candidate Management URLs
path(
"portal/candidates/<int:candidate_id>/edit/",
views.agency_portal_edit_candidate,
name="agency_portal_edit_candidate",
"portal/applications/<int:application_id>/edit/",
views.agency_portal_edit_application,
name="agency_portal_edit_application",
),
path(
"portal/candidates/<int:candidate_id>/delete/",
views.agency_portal_delete_candidate,
name="agency_portal_delete_candidate",
"portal/applications/<int:application_id>/delete/",
views.agency_portal_delete_application,
name="agency_portal_delete_application",
),
# API URLs for messaging (removed)
# path('api/agency/messages/<int:message_id>/', views.api_agency_message_detail, name='api_agency_message_detail'),
# path('api/agency/messages/<int:message_id>/mark-read/', views.api_agency_mark_message_read, name='api_agency_mark_message_read'),
# API URLs for candidate management
path(
"api/candidate/<int:candidate_id>/",
views.api_candidate_detail,
name="api_candidate_detail",
"api/application/<int:application_id>/",
views.api_application_detail,
name="api_application_detail",
),
# # Admin Notification API
# path('api/admin/notification-count/', views.api_notification_count, name='admin_notification_count'),
@ -535,10 +535,11 @@ urlpatterns = [
),
# Email composition URLs
path(
"jobs/<slug:job_slug>/candidates/compose-email/",
views.compose_candidate_email,
name="compose_candidate_email",
"jobs/<slug:job_slug>/applications/compose-email/",
views.compose_application_email,
name="compose_application_email",
),
# Message URLs
path("messages/", views.message_list, name="message_list"),
path("messages/create/", views.message_create, name="message_create"),
@ -555,15 +556,15 @@ urlpatterns = [
path("documents/<int:document_id>/delete/", views.document_delete, name="document_delete"),
path("documents/<int:document_id>/download/", views.document_download, name="document_download"),
# Candidate Document Management URLs
path("candidate/documents/upload/<slug:slug>/", views.document_upload, name="candidate_document_upload"),
path("candidate/documents/<int:document_id>/delete/", views.document_delete, name="candidate_document_delete"),
path("candidate/documents/<int:document_id>/download/", views.document_download, name="candidate_document_download"),
path('jobs/<slug:job_slug>/candidates/compose_email/', views.compose_candidate_email, name='compose_candidate_email'),
path("application/documents/upload/<slug:slug>/", views.document_upload, name="application_document_upload"),
path("application/documents/<int:document_id>/delete/", views.document_delete, name="application_document_delete"),
path("application/documents/<int:document_id>/download/", views.document_download, name="application_document_download"),
path('jobs/<slug:job_slug>/applications/compose_email/', views.compose_application_email, name='compose_application_email'),
path('interview/partcipants/<slug:slug>/',views.create_interview_participants,name='create_interview_participants'),
path('interview/email/<slug:slug>/',views.send_interview_email,name='send_interview_email'),
# Candidate Signup
path('candidate/signup/<slug:template_slug>/', views.candidate_signup, name='candidate_signup'),
path('application/signup/<slug:template_slug>/', views.application_signup, name='application_signup'),
# Password Reset
path('user/<int:pk>/password-reset/', views.portal_password_reset, name='portal_password_reset'),
@ -607,43 +608,43 @@ urlpatterns = [
),
# Candidate Meeting Scheduling/Rescheduling URLs
path(
"jobs/<slug:job_slug>/candidates/<int:candidate_pk>/schedule-meeting/",
views.schedule_candidate_meeting,
name="schedule_candidate_meeting",
"jobs/<slug:job_slug>/applications/<int:application_pk>/schedule-meeting/",
views.schedule_application_meeting,
name="schedule_application_meeting",
),
path(
"api/jobs/<slug:job_slug>/candidates/<int:candidate_pk>/schedule-meeting/",
views.api_schedule_candidate_meeting,
name="api_schedule_candidate_meeting",
"api/jobs/<slug:job_slug>/applications/<int:application_pk>/schedule-meeting/",
views.api_schedule_application_meeting,
name="api_schedule_application_meeting",
),
path(
"jobs/<slug:job_slug>/candidates/<int:candidate_pk>/reschedule-meeting/<int:interview_pk>/",
views.reschedule_candidate_meeting,
name="reschedule_candidate_meeting",
"jobs/<slug:job_slug>/applications/<int:application_pk>/reschedule-meeting/<int:interview_pk>/",
views.reschedule_application_meeting,
name="reschedule_application_meeting",
),
path(
"api/jobs/<slug:job_slug>/candidates/<int:candidate_pk>/reschedule-meeting/<int:interview_pk>/",
views.api_reschedule_candidate_meeting,
name="api_reschedule_candidate_meeting",
"api/jobs/<slug:job_slug>/applications/<int:application_pk>/reschedule-meeting/<int:interview_pk>/",
views.api_reschedule_application_meeting,
name="api_reschedule_application_meeting",
),
# New URL for simple page-based meeting scheduling
path(
"jobs/<slug:slug>/candidates/<int:candidate_pk>/schedule-meeting-page/",
views.schedule_meeting_for_candidate,
name="schedule_meeting_for_candidate",
),
path(
"jobs/<slug:slug>/candidates/<int:candidate_pk>/delete_meeting_for_candidate/<int:meeting_id>/",
views.delete_meeting_for_candidate,
name="delete_meeting_for_candidate",
"jobs/<slug:slug>/applications/<int:application_pk>/schedule-meeting-page/",
views.schedule_meeting_for_application,
name="schedule_meeting_for_application",
),
# path(
# "jobs/<slug:slug>/applications/<int:application_pk>/delete_meeting_for_application/<int:meeting_id>/",
# views.delete_meeting_for_candidate,
# name="delete_meeting_for_candidate",
# ),
path("interviews/meetings/", views.MeetingListView.as_view(), name="list_meetings"),
# 1. Onsite Reschedule URL
path(
'<slug:slug>/candidate/<int:candidate_id>/onsite/reschedule/<int:meeting_id>/',
'<slug:slug>/application/<int:application_id>/onsite/reschedule/<int:meeting_id>/',
views.reschedule_onsite_meeting,
name='reschedule_onsite_meeting'
),
@ -651,15 +652,15 @@ urlpatterns = [
# 2. Onsite Delete URL
path(
'job/<slug:slug>/candidates/<int:candidate_pk>/delete-onsite-meeting/<int:meeting_id>/',
views.delete_onsite_meeting_for_candidate,
name='delete_onsite_meeting_for_candidate'
'job/<slug:slug>/applications/<int:application_pk>/delete-onsite-meeting/<int:meeting_id>/',
views.delete_onsite_meeting_for_application,
name='delete_onsite_meeting_for_application'
),
path(
'job/<slug:slug>/candidate/<int:candidate_pk>/schedule/onsite/',
views.schedule_onsite_meeting_for_candidate,
name='schedule_onsite_meeting_for_candidate' # This is the name used in the button
'job/<slug:slug>/application/<int:application_pk>/schedule/onsite/',
views.schedule_onsite_meeting_for_application,
name='schedule_onsite_meeting_for_application' # This is the name used in the button
),
@ -667,7 +668,7 @@ urlpatterns = [
path("interviews/meetings/<slug:slug>/", views.meeting_details, name="meeting_details"),
# Email invitation URLs
path("interviews/meetings/<slug:slug>/send-candidate-invitation/", views.send_candidate_invitation, name="send_candidate_invitation"),
path("interviews/meetings/<slug:slug>/send-application-invitation/", views.send_application_invitation, name="send_application_invitation"),
path("interviews/meetings/<slug:slug>/send-participants-invitation/", views.send_participants_invitation, name="send_participants_invitation"),
]

View File

@ -201,7 +201,7 @@ class PersonCreateView(CreateView):
instance.save()
return redirect("agency_portal_persons_list")
if view == "job":
return redirect("candidate_create")
return redirect("application_create")
return super().form_valid(form)
@ -1199,7 +1199,7 @@ def delete_form_template(request, template_id):
def application_submit_form(request, template_slug):
"""Display the form as a step-by-step wizard"""
if not request.user.is_authenticated:
return redirect("candidate_signup",slug=template_slug)
return redirect("application_signup",slug=template_slug)
template = get_object_or_404(FormTemplate, slug=template_slug, is_active=True)
stage = template.stages.filter(name="Contact Information")
@ -1329,7 +1329,7 @@ def application_submit(request, template_slug):
# return redirect('application_success',slug=job.slug)
except Exception as e:
logger.error(f"Candidate creation failed,{e}")
logger.error(f"Application creation failed,{e}")
pass
return JsonResponse(
{
@ -1760,7 +1760,7 @@ def confirm_schedule_interviews_view(request, slug):
@staff_user_required
def candidate_screening_view(request, slug):
def applications_screening_view(request, slug):
"""
Manage candidate tiers and stage transitions
"""
@ -1842,7 +1842,7 @@ def candidate_screening_view(request, slug):
@staff_user_required
def candidate_exam_view(request, slug):
def applications_exam_view(request, slug):
"""
Manage candidate tiers and stage transitions
"""
@ -1852,13 +1852,13 @@ def candidate_exam_view(request, slug):
@staff_user_required
def update_candidate_exam_status(request, slug):
def update_application_exam_status(request, slug):
candidate = get_object_or_404(Application, slug=slug)
if request.method == "POST":
form = CandidateExamDateForm(request.POST, instance=candidate)
if form.is_valid():
form.save()
return redirect("candidate_exam_view", slug=candidate.job.slug)
return redirect("applications_exam_view", slug=candidate.job.slug)
else:
form = CandidateExamDateForm(request.POST, instance=candidate)
return render(
@ -1869,7 +1869,7 @@ def update_candidate_exam_status(request, slug):
@staff_user_required
def bulk_update_candidate_exam_status(request, slug):
def bulk_update_application_exam_status(request, slug):
job = get_object_or_404(JobPosting, slug=slug)
status = request.headers.get("status")
if status:
@ -1884,10 +1884,10 @@ def bulk_update_candidate_exam_status(request, slug):
except Exception as e:
print(e)
messages.success(request, f"Updated exam status selected candidates")
return redirect("candidate_exam_view", slug=job.slug)
return redirect("applications_exam_view", slug=job.slug)
def candidate_criteria_view_htmx(request, pk):
def application_criteria_view_htmx(request, pk):
candidate = get_object_or_404(Application, pk=pk)
return render(
request, "includes/candidate_modal_body.html", {"candidate": candidate}
@ -1895,18 +1895,18 @@ def candidate_criteria_view_htmx(request, pk):
@staff_user_required
def candidate_set_exam_date(request, slug):
def application_set_exam_date(request, slug):
candidate = get_object_or_404(Application, slug=slug)
candidate.exam_date = timezone.now()
candidate.save()
messages.success(
request, f"Set exam date for {candidate.name} to {candidate.exam_date}"
)
return redirect("candidate_screening_view", slug=candidate.job.slug)
return redirect("applications_screening_view", slug=candidate.job.slug)
@staff_user_required
def candidate_update_status(request, slug):
def application_update_status(request, slug):
job = get_object_or_404(JobPosting, slug=slug)
mark_as = request.POST.get("mark_as")
if mark_as != "----------":
@ -1979,13 +1979,13 @@ def candidate_update_status(request, slug):
)
messages.success(request, f"Candidates Updated")
response = HttpResponse(redirect("candidate_screening_view", slug=job.slug))
response = HttpResponse(redirect("applications_screening_view", slug=job.slug))
response.headers["HX-Refresh"] = "true"
return response
@staff_user_required
def candidate_interview_view(request, slug):
def applications_interview_view(request, slug):
job = get_object_or_404(JobPosting, slug=slug)
context = {
"job": job,
@ -1997,7 +1997,7 @@ def candidate_interview_view(request, slug):
@staff_user_required
def candidate_document_review_view(request, slug):
def applications_document_review_view(request, slug):
"""
Document review view for candidates after interview stage and before offer stage
"""
@ -2025,7 +2025,7 @@ def candidate_document_review_view(request, slug):
@staff_user_required
def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
def reschedule_meeting_for_application(request, slug, candidate_id, meeting_id):
job = get_object_or_404(JobPosting, slug=slug)
candidate = get_object_or_404(Application, pk=candidate_id)
meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)
@ -2043,7 +2043,7 @@ def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
if instance.start_time < timezone.now():
messages.error(request, "Start time must be in the future.")
return redirect(
"reschedule_meeting_for_candidate",
"reschedule_meeting_for_application",
slug=job.slug,
candidate_id=candidate_id,
meeting_id=meeting_id,
@ -2056,7 +2056,7 @@ def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
else:
messages.error(request, result["message"])
return redirect(
reverse("candidate_interview_view", kwargs={"slug": job.slug})
reverse("applications_interview_view", kwargs={"slug": job.slug})
)
context = {"job": job, "candidate": candidate, "meeting": meeting, "form": form}
@ -2064,7 +2064,7 @@ def reschedule_meeting_for_candidate(request, slug, candidate_id, meeting_id):
@staff_user_required
def delete_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
def schedule_meeting_for_application(request, slug, candidate_pk, meeting_id):
job = get_object_or_404(JobPosting, slug=slug)
candidate = get_object_or_404(Application, pk=candidate_pk)
meeting = get_object_or_404(ZoomMeetingDetails, pk=meeting_id)
@ -2078,14 +2078,14 @@ def delete_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
messages.success(request, "Meeting deleted successfully")
else:
messages.error(request, result["message"])
return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug}))
return redirect(reverse("applications_interview_view", kwargs={"slug": job.slug}))
context = {
"job": job,
"candidate": candidate,
"meeting": meeting,
"delete_url": reverse(
"delete_meeting_for_candidate",
"schedule_meeting_for_application",
kwargs={
"slug": job.slug,
"candidate_pk": candidate_pk,
@ -2125,7 +2125,7 @@ def delete_zoom_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
else:
messages.error(request, result["message"])
return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug}))
return redirect(reverse("applications_interview_view", kwargs={"slug": job.slug}))
context = {
"job": job,
@ -2218,7 +2218,7 @@ def interview_detail_view(request, slug, interview_id):
# Candidate Meeting Scheduling/Rescheduling Views
@require_POST
def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
def api_schedule_application_meeting(request, job_slug, candidate_pk):
"""
Handle POST request to schedule a Zoom meeting for a candidate via HTMX.
Returns JSON response for modal update.
@ -2298,23 +2298,23 @@ def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
return JsonResponse({"success": False, "error": result["message"]}, status=400)
def schedule_candidate_meeting(request, job_slug, candidate_pk):
def schedule_application_meeting(request, job_slug, candidate_pk):
"""
GET: Render modal form to schedule a meeting. (For HTMX)
POST: Handled by api_schedule_candidate_meeting.
POST: Handled by api_schedule_application_meeting.
"""
job = get_object_or_404(JobPosting, slug=job_slug)
candidate = get_object_or_404(Application, pk=candidate_pk, job=job)
if request.method == "POST":
return api_schedule_candidate_meeting(request, job_slug, candidate_pk)
return api_schedule_application_meeting(request, job_slug, candidate_pk)
# GET request - render the form snippet for HTMX
context = {
"job": job,
"candidate": candidate,
"action_url": reverse(
"api_schedule_candidate_meeting",
"api_schedule_application_meeting",
kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk},
),
"scheduled_interview": None, # Explicitly None for schedule
@ -2324,7 +2324,7 @@ def schedule_candidate_meeting(request, job_slug, candidate_pk):
@require_http_methods(["GET", "POST"])
def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
def api_schedule_application_meeting(request, job_slug, candidate_pk):
"""
Handles GET to render form and POST to process scheduling.
"""
@ -2337,7 +2337,7 @@ def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
"job": job,
"candidate": candidate,
"action_url": reverse(
"api_schedule_candidate_meeting",
"api_schedule_application_meeting",
kwargs={"job_slug": job_slug, "candidate_pk": candidate_pk},
),
"scheduled_interview": None,
@ -2408,7 +2408,7 @@ def api_schedule_candidate_meeting(request, job_slug, candidate_pk):
@require_http_methods(["GET", "POST"])
def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
def api_reschedule_application_meeting(request, job_slug, candidate_pk, interview_pk):
"""
Handles GET to render form and POST to process rescheduling.
"""
@ -2434,7 +2434,7 @@ def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_
"scheduled_interview": scheduled_interview, # Pass for conditional logic in template
"initial_data": initial_data,
"action_url": reverse(
"api_reschedule_candidate_meeting",
"api_reschedule_application_meeting",
kwargs={
"job_slug": job_slug,
"candidate_pk": candidate_pk,
@ -2530,14 +2530,14 @@ def api_reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_
return JsonResponse({"success": False, "error": result["message"]}, status=400)
# The original schedule_candidate_meeting and reschedule_candidate_meeting (without api_ prefix)
# The original schedule_application_meeting and reschedule_application_meeting (without api_ prefix)
# can be removed if their only purpose was to be called by the JS onclicks.
# If they were intended for other direct URL access, they can be kept as simple redirects
# or wrappers to the api_ versions.
# For now, let's assume the api_ versions are the primary ones for HTMX.
def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
def reschedule_application_meeting(request, job_slug, candidate_pk, interview_pk):
"""
Handles GET to display a form for rescheduling a meeting.
Handles POST to process the rescheduling of a meeting.
@ -2592,7 +2592,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
else "",
"initial_duration": new_duration,
"action_url": reverse(
"reschedule_candidate_meeting",
"reschedule_application_meeting",
kwargs={
"job_slug": job_slug,
"candidate_pk": candidate_pk,
@ -2672,7 +2672,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
f"Meeting for {application.name} rescheduled. (Note: Could not refresh all details from Zoom.)",
)
return redirect("candidate_interview_view", slug=job.slug)
return redirect("applications_interview_view", slug=job.slug)
else:
messages.error(
request,
@ -2693,7 +2693,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
else "",
"initial_duration": new_duration,
"action_url": reverse(
"reschedule_candidate_meeting",
"reschedule_application_meeting",
kwargs={
"job_slug": job_slug,
"candidate_pk": candidate_pk,
@ -2722,7 +2722,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
),
"initial_duration": request.POST.get("duration", new_duration),
"action_url": reverse(
"reschedule_candidate_meeting",
"reschedule_application_meeting",
kwargs={
"job_slug": job_slug,
"candidate_pk": candidate_pk,
@ -2749,7 +2749,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
"application": application,
"scheduled_interview": scheduled_interview, # Pass to template for title/differentiation
"action_url": reverse(
"reschedule_candidate_meeting",
"reschedule_application_meeting",
kwargs={
"job_slug": job_slug,
"candidate_pk": candidate_pk,
@ -2761,7 +2761,7 @@ def reschedule_candidate_meeting(request, job_slug, candidate_pk, interview_pk):
)
def schedule_meeting_for_candidate(request, slug, candidate_pk):
def schedule_meeting_for_application(request, slug, candidate_pk):
"""
Handles GET to display a simple form for scheduling a meeting for a candidate.
Handles POST to process the form, create a meeting, and redirect back.
@ -2784,7 +2784,7 @@ def schedule_meeting_for_candidate(request, slug, candidate_pk):
if start_time_val <= timezone.now():
messages.error(request, "Start time must be in the future.")
# Re-render form with error and initial data
return redirect("candidate_interview_view", slug=job.slug)
return redirect("applications_interview_view", slug=job.slug)
# return render(request, "recruitment/schedule_meeting_form.html", {
# 'form': form,
# 'job': job,
@ -2829,7 +2829,7 @@ def schedule_meeting_for_candidate(request, slug, candidate_pk):
status="scheduled",
)
messages.success(request, f"Meeting scheduled with {candidate.name}.")
return redirect("candidate_interview_view", slug=job.slug)
return redirect("applications_interview_view", slug=job.slug)
else:
messages.error(
request,
@ -3232,7 +3232,7 @@ def delete_meeting_comment(request, slug, comment_id):
@staff_user_required
def set_meeting_candidate(request, slug):
def set_meeting_application(request, slug):
meeting = get_object_or_404(ZoomMeetingDetails, slug=slug)
if request.method == "POST" and "HX-Request" not in request.headers:
form = InterviewForm(request.POST)
@ -3254,7 +3254,7 @@ def set_meeting_candidate(request, slug):
form.fields["candidate"].queryset = Application.objects.none()
form.fields["job"].widget.attrs.update(
{
"hx-get": reverse("set_meeting_candidate", kwargs={"slug": slug}),
"hx-get": reverse("set_meeting_application", kwargs={"slug": slug}),
"hx-target": "#div_id_candidate",
"hx-select": "#div_id_candidate",
"hx-swap": "outerHTML",
@ -3708,7 +3708,7 @@ def agency_delete(request, slug):
@staff_user_required
def agency_candidates(request, slug):
def agency_applications(request, slug):
"""View all candidates from a specific agency"""
agency = get_object_or_404(HiringAgency, slug=slug)
candidates = Application.objects.filter(hiring_agency=agency).order_by(
@ -4011,7 +4011,7 @@ def portal_login(request):
return redirect("agency_portal_dashboard")
if request.user.user_type == "candidate":
print(request.user)
return redirect("candidate_portal_dashboard")
return redirect("applicant_portal_dashboard")
if request.method == "POST":
form = PortalLoginForm(request.POST)
@ -4052,7 +4052,7 @@ def portal_login(request):
# request,
# f"Welcome, {user.candidate_profile.first_name}!",
# )
# return redirect("candidate_portal_dashboard")
# return redirect("applicant_portal_dashboard")
# else:
# messages.error(
# request, "No candidate profile found for this user."
@ -4075,7 +4075,7 @@ def portal_login(request):
@login_required
@candidate_user_required
def candidate_portal_dashboard(request):
def applicant_portal_dashboard(request):
"""Candidate portal dashboard"""
if not request.user.is_authenticated:
return redirect("account_login")
@ -4113,7 +4113,7 @@ def candidate_portal_dashboard(request):
@login_required
def candidate_application_detail(request, slug):
def applicant_application_detail(request, slug):
"""View detailed information about a specific application"""
if not request.user.is_authenticated:
return redirect("account_login")
@ -4278,7 +4278,7 @@ def agency_portal_dashboard(request):
@agency_user_required
def agency_portal_submit_candidate_page(request, slug):
def agency_portal_submit_application_page(request, slug):
"""Dedicated page for submitting a candidate"""
# assignment_id = request.session.get("agency_assignment_id")
# if not assignment_id:
@ -4345,7 +4345,7 @@ def agency_portal_submit_candidate_page(request, slug):
@agency_user_required
def agency_portal_submit_candidate(request):
def agency_portal_submit_application(request):
"""Handle candidate submission via AJAX (for embedded form)"""
assignment_id = request.session.get("agency_assignment_id")
if not assignment_id:
@ -4517,7 +4517,7 @@ def agency_assignment_detail_admin(request, slug):
@agency_user_required
def agency_portal_edit_candidate(request, candidate_id):
def agency_portal_edit_application(request, candidate_id):
"""Edit a candidate for agency portal"""
assignment_id = request.session.get("agency_assignment_id")
if not assignment_id:
@ -4578,7 +4578,7 @@ def agency_portal_edit_candidate(request, candidate_id):
@agency_user_required
def agency_portal_delete_candidate(request, candidate_id):
def agency_portal_delete_application(request, candidate_id):
"""Delete a candidate for agency portal"""
assignment_id = request.session.get("agency_assignment_id")
if not assignment_id:
@ -4986,7 +4986,7 @@ def document_upload(request, slug):
}
})
return redirect("candidate_portal_dashboard")
return redirect("applicant_portal_dashboard")
else:
# Create document for Application (existing logic)
document = Document.objects.create(
@ -5016,15 +5016,15 @@ def document_upload(request, slug):
}
})
if upload_target == 'person':
return redirect("candidate_portal_dashboard")
return redirect("applicant_portal_dashboard")
else:
return redirect("candidate_application_detail", application_slug=application.slug)
return redirect("applicant_application_detail", application_slug=application.slug)
# Handle GET request for AJAX
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
return JsonResponse({"success": False, "error": "Method not allowed"})
return redirect("candidate_detail", slug=application.job.slug)
return redirect("application_detail", slug=application.job.slug)
@login_required
def document_delete(request, document_id):
@ -5043,7 +5043,7 @@ def document_delete(request, document_id):
)
return JsonResponse({"success": False, "error": "Permission denied"})
job_slug = document.content_object.job.slug
redirect_url = "candidate_portal_dashboard" if request.user.user_type == "candidate" else "job_detail"
redirect_url = "applicant_portal_dashboard" if request.user.user_type == "candidate" else "job_detail"
elif hasattr(document.content_object, "person"):
# Person document
if request.user.user_type == "candidate":
@ -5053,7 +5053,7 @@ def document_delete(request, document_id):
request, "You can only delete your own documents."
)
return JsonResponse({"success": False, "error": "Permission denied"})
redirect_url = "candidate_portal_dashboard"
redirect_url = "applicant_portal_dashboard"
else:
# Handle other content object types
messages.error(request, "You don't have permission to delete this document.")
@ -5070,7 +5070,7 @@ def document_delete(request, document_id):
{"success": True, "message": "Document deleted successfully!"}
)
else:
return redirect("candidate_detail", slug=job_slug)
return redirect("application_detail", slug=job_slug)
return JsonResponse({"success": False, "error": "Method not allowed"})
@ -5091,7 +5091,7 @@ def document_download(request, document_id):
)
return JsonResponse({"success": False, "error": "Permission denied"})
job_slug = document.content_object.job.slug
redirect_url = "candidate_detail" if request.user.user_type == "candidate" else "job_detail"
redirect_url = "application_detail" if request.user.user_type == "candidate" else "job_detail"
elif hasattr(document.content_object, "person"):
# Person document
if request.user.user_type == "candidate":
@ -5101,7 +5101,7 @@ def document_download(request, document_id):
request, "You can only download your own documents."
)
return JsonResponse({"success": False, "error": "Permission denied"})
redirect_url = "candidate_portal_dashboard"
redirect_url = "applicant_portal_dashboard"
else:
# Handle other content object types
messages.error(request, "You don't have permission to download this document.")
@ -5210,7 +5210,7 @@ def agency_access_link_reactivate(request, slug):
@agency_user_required
def api_candidate_detail(request, candidate_id):
def api_application_detail(request, candidate_id):
"""API endpoint to get candidate details for agency portal"""
try:
# Get candidate from session-based agency access
@ -5248,7 +5248,7 @@ def api_candidate_detail(request, candidate_id):
@staff_user_required
def compose_candidate_email(request, job_slug):
def compose_application_email(request, job_slug):
"""Compose email to participants about a candidate"""
from .email_service import send_bulk_email
@ -5326,7 +5326,7 @@ def compose_candidate_email(request, job_slug):
response = HttpResponse(status=200)
response.headers["HX-Refresh"] = "true"
return response
# return redirect("candidate_interview_view", slug=job.slug)
# return redirect("applications_interview_view", slug=job.slug)
else:
messages.error(
request,
@ -5556,14 +5556,14 @@ def source_toggle_status(request, slug):
return JsonResponse({"success": False, "error": "Method not allowed"})
def candidate_signup(request, slug):
from .forms import CandidateSignupForm
def application_signup(request, slug):
from .forms import ApplicantSignupForm
form_template = get_object_or_404(FormTemplate, slug=slug)
job = form_template.job
if request.method == "POST":
form = CandidateSignupForm(request.POST)
form = ApplicantSignupForm(request.POST)
if form.is_valid():
try:
first_name = form.cleaned_data["first_name"]
@ -5599,13 +5599,13 @@ def candidate_signup(request, slug):
messages.error(request, f"Error creating application: {str(e)}")
return render(
request,
"recruitment/candidate_signup.html",
"recruitment/applicant_signup.html",
{"form": form, "job": job},
)
form = CandidateSignupForm()
form = ApplicantSignupForm()
return render(
request, "recruitment/candidate_signup.html", {"form": form, "job": job}
request, "recruitment/applicant_signup.html", {"form": form, "job": job}
)
@ -5959,7 +5959,7 @@ def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
instance.save()
messages.success(request, "Onsite meeting successfully rescheduled! ✅")
return redirect(reverse("candidate_interview_view", kwargs={'slug': job.slug}))
return redirect(reverse("applications_interview_view", kwargs={'slug': job.slug}))
else:
form = OnsiteReshuduleForm(instance=onsite_meeting)
@ -5976,7 +5976,7 @@ def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
# recruitment/views.py
@staff_user_required
def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id):
def delete_onsite_meeting_for_application(request, slug, candidate_pk, meeting_id):
"""
Deletes a specific Onsite Location Details instance.
This does not require an external API call.
@ -5993,7 +5993,7 @@ def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id)
meeting.delete()
messages.success(request, f"Onsite meeting for {candidate.name} deleted successfully.")
return redirect(reverse("candidate_interview_view", kwargs={"slug": job.slug}))
return redirect(reverse("applications_interview_view", kwargs={"slug": job.slug}))
context = {
"job": job,
@ -6001,7 +6001,7 @@ def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id)
"meeting": meeting,
"location_type": "Onsite",
"delete_url": reverse(
"delete_onsite_meeting_for_candidate", # Use the specific new URL name
"delete_onsite_meeting_for_application", # Use the specific new URL name
kwargs={
"slug": job.slug,
"candidate_pk": candidate_pk,
@ -6013,14 +6013,14 @@ def delete_onsite_meeting_for_candidate(request, slug, candidate_pk, meeting_id)
def schedule_onsite_meeting_for_candidate(request, slug, candidate_pk):
def schedule_onsite_meeting_for_application(request, slug, candidate_pk):
"""
Handles scheduling a NEW Onsite Interview for a candidate using OnsiteScheduleForm.
"""
job = get_object_or_404(JobPosting, slug=slug)
candidate = get_object_or_404(Application, pk=candidate_pk)
action_url = reverse('schedule_onsite_meeting_for_candidate',
action_url = reverse('schedule_onsite_meeting_for_application',
kwargs={'slug': job.slug, 'candidate_pk': candidate.pk})
if request.method == 'POST':
@ -6058,7 +6058,7 @@ def schedule_onsite_meeting_for_candidate(request, slug, candidate_pk):
)
messages.success(request, "Onsite interview scheduled successfully. ✅")
return redirect(reverse("candidate_interview_view", kwargs={'slug': job.slug}))
return redirect(reverse("applications_interview_view", kwargs={'slug': job.slug}))
else:
# GET Request: Initialize the hidden fields with the correct objects
@ -6139,7 +6139,7 @@ def meeting_details(request, slug):
@login_required
def send_candidate_invitation(request, slug):
def send_application_invitation(request, slug):
"""Send invitation email to the candidate"""
meeting = get_object_or_404(InterviewLocation, slug=slug)

View File

@ -187,7 +187,7 @@ class ApplicationCreateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessa
model = models.Application
form_class = forms.ApplicationForm
template_name = 'recruitment/candidate_create.html'
success_url = reverse_lazy('candidate_list')
success_url = reverse_lazy('application_list')
success_message = 'Candidate created successfully.'
def get_initial(self):
@ -216,7 +216,7 @@ class ApplicationUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessa
model = models.Application
form_class = forms.ApplicationForm
template_name = 'recruitment/candidate_update.html'
success_url = reverse_lazy('candidate_list')
success_url = reverse_lazy('application_list')
success_message = 'Candidate updated successfully.'
slug_url_kwarg = 'slug'
@ -224,7 +224,7 @@ class ApplicationUpdateView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessa
class ApplicationDeleteView(LoginRequiredMixin, StaffRequiredMixin, SuccessMessageMixin, DeleteView):
model = models.Application
template_name = 'recruitment/candidate_delete.html'
success_url = reverse_lazy('candidate_list')
success_url = reverse_lazy('application_list')
success_message = 'Candidate deleted successfully.'
slug_url_kwarg = 'slug'
@ -240,7 +240,7 @@ def retry_scoring_view(request,slug):
hook='recruitment.hooks.callback_ai_parsing',
sync=True,
)
return redirect('candidate_detail', slug=application.slug)
return redirect('application_detail', slug=application.slug)
@ -253,7 +253,7 @@ def training_list(request):
@login_required
@staff_user_required
def candidate_detail(request, slug):
def application_detail(request, slug):
from rich.json import JSON
candidate = get_object_or_404(models.Application, slug=slug)
try:
@ -270,7 +270,7 @@ def candidate_detail(request, slug):
# parsed = JSON(json.dumps(parsed), indent=2, highlight=True, skip_keys=False, ensure_ascii=False, check_circular=True, allow_nan=True, default=None, sort_keys=False)
# parsed = json_to_markdown_table([parsed])
return render(request, 'recruitment/candidate_detail.html', {
return render(request, 'recruitment/application_detail.html', {
'candidate': candidate,
'parsed': parsed,
'stage_form': stage_form,
@ -279,13 +279,13 @@ def candidate_detail(request, slug):
@login_required
@staff_user_required
def candidate_resume_template_view(request, slug):
def application_resume_template_view(request, slug):
"""Display formatted resume template for a candidate"""
application = get_object_or_404(models.Application, slug=slug)
if not request.user.is_staff:
messages.error(request, _("You don't have permission to view this page."))
return redirect('candidate_list')
return redirect('application_list')
return render(request, 'recruitment/candidate_resume_template.html', {
'application': application
@ -293,7 +293,7 @@ def candidate_resume_template_view(request, slug):
@login_required
@staff_user_required
def candidate_update_stage(request, slug):
def application_update_stage(request, slug):
"""Handle HTMX stage update requests"""
application = get_object_or_404(models.Application, slug=slug)
form = forms.ApplicationStageForm(request.POST, instance=application)
@ -302,7 +302,7 @@ def candidate_update_stage(request, slug):
application.stage = stage_value
application.save(update_fields=['stage'])
messages.success(request,"application Stage Updated")
return redirect("candidate_detail",slug=application.slug)
return redirect("application_detail",slug=application.slug)
class TrainingListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
model = models.TrainingMaterial
@ -637,7 +637,7 @@ def dashboard_view(request):
@login_required
@staff_user_required
def candidate_offer_view(request, slug):
def applications_offer_view(request, slug):
"""View for candidates in the Offer stage"""
job = get_object_or_404(models.JobPosting, slug=slug)
@ -667,7 +667,7 @@ def candidate_offer_view(request, slug):
@login_required
@staff_user_required
def candidate_hired_view(request, slug):
def applications_hired_view(request, slug):
"""View for hired candidates"""
job = get_object_or_404(models.JobPosting, slug=slug)
@ -697,7 +697,7 @@ def candidate_hired_view(request, slug):
@login_required
@staff_user_required
def update_candidate_status(request, job_slug, candidate_slug, stage_type, status):
def update_application_status(request, job_slug, candidate_slug, stage_type, status):
"""Handle exam/interview/offer status updates"""
from django.utils import timezone
@ -723,7 +723,7 @@ def update_candidate_status(request, job_slug, candidate_slug, stage_type, statu
candidate.offer_date = timezone.now()
candidate.save(update_fields=['offer_status', 'offer_date'])
return render(request,'recruitment/partials/offer-results.html',{'candidate':candidate,'job':job})
return redirect('candidate_detail', candidate.slug)
return redirect('application_detail', candidate.slug)
else:
if stage_type == 'exam':
return render(request,"includes/candidate_update_exam_form.html",{'candidate':candidate,'job':job})
@ -765,7 +765,7 @@ STAGE_CONFIG = {
@login_required
@staff_user_required
def export_candidates_csv(request, job_slug, stage):
def export_applications_csv(request, job_slug, stage):
"""Export candidates for a specific stage as CSV"""
job = get_object_or_404(models.JobPosting, slug=job_slug)
@ -905,7 +905,7 @@ def export_candidates_csv(request, job_slug, stage):
@login_required
@staff_user_required
def sync_hired_candidates(request, job_slug):
def sync_hired_applications(request, job_slug):
"""Sync hired candidates to external sources using Django-Q"""
from django_q.tasks import async_task
from .tasks import sync_hired_candidates_task

View File

@ -323,7 +323,7 @@
<a class="nav-link text-secondary" href="{% url 'applicant_profile' %}">{% translate "Applications" %}</a>
</li> {% endcomment %}
<li class="nav-item">
<a class="nav-link text-secondary" href="{% url 'candidate_portal_dashboard' %}">{% translate "Profile" %}</a>
<a class="nav-link text-secondary" href="{% url 'applicant_portal_dashboard' %}">{% translate "Profile" %}</a>
</li>
<li class="nav-item">
<a class="nav-link text-secondary" href="{% url 'kaauh_career' %}">{% translate "Careers" %}</a>

View File

@ -253,7 +253,7 @@
</a>
</li>
<li class="nav-item me-lg-4">
<a class="nav-link {% if request.resolver_match.url_name == 'candidate_list' %}active{% endif %}" href="{% url 'candidate_list' %}">
<a class="nav-link {% if request.resolver_match.url_name == 'application_list' %}active{% endif %}" href="{% url 'application_list' %}">
<span class="d-flex align-items-center gap-2">
<i class="fas fa-user-tie me-2"></i>
{% trans "Applications" %}

View File

@ -1,5 +1,5 @@
{% load i18n %}
{% url 'update_candidate_exam_status' slug=candidate.slug as url %}
{% url 'update_application_exam_status' slug=candidate.slug as url %}
<form data-on-submit="@post('{{url}}', {contentType: 'form', headers: {'X-CSRFToken': '{{ csrf_token }}'}})">
{% csrf_token %}
{{ form.as_p }}

View File

@ -1,5 +1,5 @@
{% load i18n %}
<form id="exam-update-form" hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'Failed' %}" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}"
<form id="exam-update-form" hx-post="{% url 'update_application_status' job.slug candidate.slug 'exam' 'Failed' %}" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}"
hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }">
<div class="d-flex justify-content-center align-items-center gap-2">
<div class="form-check d-flex align-items-center gap-2">

View File

@ -1,10 +1,10 @@
{% load i18n %}
<div class="d-flex justify-content-center align-items-center gap-2" hx-swap='outerHTML' hx-target="#interview-result-{{ candidate.pk }}"
hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }">
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'Passed' %}" class="btn btn-outline-secondary">
<a hx-post="{% url 'update_application_status' job.slug candidate.slug 'interview' 'Passed' %}" class="btn btn-outline-secondary">
<i class="fas fa-check me-1"></i> {% trans "Passed" %}
</a>
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'Failed' %}" class="btn btn-danger">
<a hx-post="{% url 'update_application_status' job.slug candidate.slug 'interview' 'Failed' %}" class="btn btn-danger">
<i class="fas fa-times me-1"></i> {% trans "Failed" %}
</a>
</div>

View File

@ -1,10 +1,10 @@
{% load i18n %}
<div class="d-flex justify-content-center align-items-center gap-2" hx-swap='outerHTML' hx-target="#status-result-{{ candidate.pk }}"
hx-on::after-request="const modal = bootstrap.Modal.getInstance(document.getElementById('candidateviewModal')); if (modal) { modal.hide(); }">
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Accepted' %}" class="btn btn-outline-secondary">
<a hx-post="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Accepted' %}" class="btn btn-outline-secondary">
<i class="fas fa-check me-1"></i> {% trans "Accepted" %}
</a>
<a hx-post="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Rejected' %}" class="btn btn-danger">
<a hx-post="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Rejected' %}" class="btn btn-danger">
<i class="fas fa-times me-1"></i> {% trans "Rejected" %}
</a>
</div>

View File

@ -17,7 +17,7 @@
<div class="card">
<div class="card-body">
<form hx-boost="true" method="post" id="email-compose-form" action="{% url 'compose_candidate_email' job.slug %}"
<form hx-boost="true" method="post" id="email-compose-form" action="{% url 'compose_application_email' job.slug %}"
hx-include="#candidate-form"
hx-target="#messageContent"
hx-select="#messageContent"

View File

@ -91,7 +91,7 @@
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title flex-grow-1 me-3">
<a href="{% url 'candidate_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a>
<a href="{% url 'application_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a>
</h5>
<span class="status-badge bg-{{ interview.status }}">
{{ interview.status|title }}
@ -169,7 +169,7 @@
<tr>
<td>
<strong class="text-primary-theme">
<a href="{% url 'candidate_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a>
<a href="{% url 'application_detail' interview.candidate.slug %}" class="text-decoration-none text-primary-theme">{{ interview.candidate.name }}</a>
</strong>
</td>
<td>

View File

@ -127,7 +127,7 @@
</nav>
</div>
<div>
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
<a href="{% url 'application_create_for_job' job.slug %}" class="btn btn-main-action">
<i class="fas fa-user-plus"></i> {% trans "Add New Applicant" %}
</a>
</div>
@ -186,7 +186,7 @@
</button>
</div>
<div class="col-md-3 d-flex align-items-end">
<a href="{% url 'job_candidates_list' job.slug %}" class="btn btn-outline-secondary w-100">
<a href="{% url 'job_applications_list' job.slug %}" class="btn btn-outline-secondary w-100">
<i class="fas fa-times"></i> {% trans "Clear Filters" %}
</a>
</div>
@ -250,16 +250,16 @@
<td class="text-secondary small">{{ candidate.created_at|date:"M d, Y" }}</td>
<td class="text-center pe-3">
<div class="btn-group" role="group">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'View' %}">
<a href="{% url 'application_detail' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
<a href="{% url 'application_update' candidate.slug %}" class="btn btn-outline-secondary btn-sm" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
<i class="fas fa-trash"></i>
</button>
@ -345,17 +345,17 @@
</div>
<div class="card-footer">
<div class="d-flex gap-2">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary w-100">
<a href="{% url 'application_detail' candidate.slug %}" class="btn btn-outline-secondary w-100">
<i class="fas fa-eye"></i> {% trans "View Profile" %}
</a>
{% if user.is_staff %}
<div class="btn-group" role="group">
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
<a href="{% url 'application_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.first_name }} {{ candidate.last_name }}">
<i class="fas fa-trash"></i>
</button>
@ -375,7 +375,7 @@
<i class="fas fa-user-slash fa-3x text-muted mb-3"></i>
<h4 class="text-muted">{% trans "No applicants found" %}</h4>
<p class="text-secondary">{% trans "There are no candidates who have applied for this position yet." %}</p>
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action mt-3">
<a href="{% url 'application_create_for_job' job.slug %}" class="btn btn-main-action mt-3">
<i class="fas fa-user-plus"></i> {% trans "Add First Applicant" %}
</a>
</div>

View File

@ -325,10 +325,10 @@
<h5 class="mb-3">{% trans "Total Applicants" %} (<span id="total_candidates">{{ total_applicants }}</span>)</h5>
<div class="d-grid gap-3">
<a href="{% url 'candidate_create_for_job' job.slug %}" class="btn btn-main-action">
<a href="{% url 'application_create_for_job' job.slug %}" class="btn btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Create Applicant" %}
</a>
<a href="{% url 'candidate_screening_view' job.slug %}" class="btn btn-main-action">
<a href="{% url 'applications_screening_view' job.slug %}" class="btn btn-main-action">
<i class="fas fa-layer-group me-1"></i> {% trans "Manage Applicants" %}
</a>

View File

@ -330,12 +330,12 @@
</td>
{# CANDIDATE MANAGEMENT DATA #}
<td class="candidate-data-cell text-primary-theme"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-primary-theme">{% if job.all_candidates.count %}{{ job.all_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-info"><a href="{% url 'candidate_screening_view' job.slug %}" class="text-info">{% if job.screening_candidates.count %}{{ job.screening_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_exam_view' job.slug %}" class="text-success">{% if job.exam_candidates.count %}{{ job.exam_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_interview_view' job.slug %}" class="text-success">{% if job.interview_candidates.count %}{{ job.interview_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_document_review_view' job.slug %}" class="text-success">{% if job.document_review_candidates.count %}{{ job.document_review_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'candidate_offer_view' job.slug %}" class="text-success">{% if job.offer_candidates.count %}{{ job.offer_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-primary-theme"><a href="{% url 'applications_screening_view' job.slug %}" class="text-primary-theme">{% if job.all_candidates.count %}{{ job.all_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-info"><a href="{% url 'applications_screening_view' job.slug %}" class="text-info">{% if job.screening_candidates.count %}{{ job.screening_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'applications_exam_view' job.slug %}" class="text-success">{% if job.exam_candidates.count %}{{ job.exam_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'applications_interview_view' job.slug %}" class="text-success">{% if job.interview_candidates.count %}{{ job.interview_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'applications_document_review_view' job.slug %}" class="text-success">{% if job.document_review_candidates.count %}{{ job.document_review_candidates.count }}{% else %}-{% endif %}</a></td>
<td class="candidate-data-cell text-success"><a href="{% url 'applications_offer_view' job.slug %}" class="text-success">{% if job.offer_candidates.count %}{{ job.offer_candidates.count }}{% else %}-{% endif %}</a></td>
</tr>
{% endfor %}
</tbody>

View File

@ -102,7 +102,7 @@
<div class="progress-stages">
<div class="d-flex justify-content-between align-items-center">
{% comment %} STAGE 1: Applied {% endcomment %}
<a href="{% url 'candidate_screening_view' job.slug %}"
<a href="{% url 'applications_screening_view' job.slug %}"
class="stage-item {% if current_stage == 'Applied' %}active{% endif %}"
data-stage="Applied">
<div class="stage-icon">
@ -116,7 +116,7 @@
<div class="stage-connector {% if current_stage == 'Exam' or current_stage == 'Interview' or current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 2: Exam {% endcomment %}
<a href="{% url 'candidate_exam_view' job.slug %}"
<a href="{% url 'applications_exam_view' job.slug %}"
class="stage-item {% if current_stage == 'Exam' %}active{% endif %}"
data-stage="Exam">
<div class="stage-icon">
@ -130,7 +130,7 @@
<div class="stage-connector {% if current_stage == 'Interview' or current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 3: Interview {% endcomment %}
<a href="{% url 'candidate_interview_view' job.slug %}"
<a href="{% url 'applications_interview_view' job.slug %}"
class="stage-item {% if current_stage == 'Interview' %}active{% endif %}"
data-stage="Interview">
<div class="stage-icon">
@ -144,7 +144,7 @@
<div class="stage-connector {% if current_stage == 'Document Review' or current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 4: Document Review {% endcomment %}
<a href="{% url 'candidate_document_review_view' job.slug %}"
<a href="{% url 'applications_document_review_view' job.slug %}"
class="stage-item {% if current_stage == 'Document Review' %}active{% endif %} {% if current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"
data-stage="Document Review">
<div class="stage-icon">
@ -158,7 +158,7 @@
<div class="stage-connector {% if current_stage == 'Offer' or current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 5: Offer {% endcomment %}
<a href="{% url 'candidate_offer_view' job.slug %}"
<a href="{% url 'applications_offer_view' job.slug %}"
class="stage-item {% if current_stage == 'Offer' %}active{% endif %} {% if current_stage == 'Hired' %}completed{% endif %}"
data-stage="Offer">
<div class="stage-icon">
@ -172,7 +172,7 @@
<div class="stage-connector {% if current_stage == 'Hired' %}completed{% endif %}"></div>
{% comment %} STAGE 6: Hired {% endcomment %}
<a href="{% url 'candidate_hired_view' job.slug %}"
<a href="{% url 'applications_hired_view' job.slug %}"
class="stage-item {% if current_stage == 'Hired' %}active{% endif %}"
data-stage="Hired">
<div class="stage-icon">

View File

@ -290,7 +290,7 @@
<span class="status-badge bg-primary-theme text-white">{{ meeting.type|title }}</span>
</td>
<td>
<a class="text-primary text-decoration-none" href="{% url 'candidate_detail' meeting.interview.application.person.slug %}">{{ meeting.interview.application.person.full_name }} <i class="fas fa-link"></i></a>
<a class="text-primary text-decoration-none" href="{% url 'application_detail' meeting.interview.application.person.slug %}">{{ meeting.interview.application.person.full_name }} <i class="fas fa-link"></i></a>
</td>
<td>
<a class="text-primary text-decoration-none" href="{% url 'job_detail' meeting.interview.job.slug %}">{{ meeting.interview.job.title }} <i class="fas fa-link"></i></a>

View File

@ -218,7 +218,7 @@ body {
</a>
{# Send Candidate Invitation Button #}
<form method="post" action="{% url 'send_candidate_invitation' meeting.slug %}" style="display: inline;">
<form method="post" action="{% url 'send_application_invitation' meeting.slug %}" style="display: inline;">
{% csrf_token %}
<button type="submit" class="btn btn-outline-info btn-sm" onclick="return confirm('{% trans "Send invitation email to the candidate?" %}')">
<i class="fas fa-envelope me-1"></i> {% trans "Send Candidate Invitation" %}

View File

@ -19,7 +19,7 @@
</div>
<div>
<form method="post" id="updateMeeting" action="{% url 'reschedule_meeting_for_candidate' job.slug candidate.pk meeting.pk %}">
<form method="post" id="updateMeeting" action="{% url 'reschedule_meeting_for_application' job.slug candidate.pk meeting.pk %}">
{% csrf_token %}
<div class="mb-3">

View File

@ -20,7 +20,7 @@
</div>
<div>
<form method="post" action="{% url 'schedule_meeting_for_candidate' job.slug candidate.pk %}">
<form method="post" action="{% url 'schedule_meeting_for_application' job.slug candidate.pk %}">
{% csrf_token %}
<div class="mb-3">
<label for="{{ form.topic.id_for_label }}" class="form-label small">

View File

@ -1,5 +1,5 @@
{% load i18n crispy_forms_tags %}
<form action="{% url 'set_meeting_candidate' meeting.slug %}" method="post" class="d-flex flex-column gap-2 py-2 px-4">
<form action="{% url 'set_meeting_application' meeting.slug %}" method="post" class="d-flex flex-column gap-2 py-2 px-4">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn bg-primary-theme text-white">{% trans "Save" %}</button>

View File

@ -412,7 +412,7 @@
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="mb-1">
<a href="{% url 'candidate_detail' application.slug %}"
<a href="{% url 'application_detail' application.slug %}"
class="text-decoration-none text-secondary">
{{ application.job.title }}
</a>

View File

@ -55,7 +55,7 @@
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
<div class="container-fluid" style="max-width: 1600px;">
{% if request.user.user_type == 'candidate' %}
<a class="navbar-brand text-white" href="{% url 'candidate_portal_dashboard' %}" aria-label="Applicant Dashboard">
<a class="navbar-brand text-white" href="{% url 'applicant_portal_dashboard' %}" aria-label="Applicant Dashboard">
<img src="{% static 'image/kaauh_green1.png' %}" alt="{% trans 'kaauh logo green bg' %}" style="width: 40px; height: 40px;">
<span class="ms-3 d-none d-md-inline fw-semibold">{% trans "Applicant Portal" %}</span>
</a>
@ -106,7 +106,7 @@
</li>
{% elif request.user.user_type == 'candidate' %}
<li class="nav-item">
<a class="nav-link text-white" href="{% url 'candidate_portal_dashboard' %}">
<a class="nav-link text-white" href="{% url 'applicant_portal_dashboard' %}">
<i class="fas fa-tachometer-alt me-1"></i> {% trans "Dashboard" %}
</a>
</li>

View File

@ -277,7 +277,7 @@
<span class="small text-muted">{{ candidate.created_at|date:"M d, Y" }}</span>
</td>
<td class="px-4 text-end">
<a href="{% url 'candidate_detail' candidate.slug %}"
<a href="{% url 'application_detail' candidate.slug %}"
class="btn btn-sm btn-outline-primary" title="{% trans 'View Details' %}">
<i class="fas fa-eye"></i>
</a>

View File

@ -114,7 +114,7 @@
<a href="{% url 'agency_portal_dashboard' %}" class="btn btn-outline-secondary btn-sm me-2">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Dashboard" %}
</a>
<a href="{% url 'agency_portal_submit_candidate_page' assignment.slug %}" class="btn btn-sm btn-main-action {% if assignment.is_full %}disabled{% endif %}" >
<a href="{% url 'agency_portal_submit_application_page' assignment.slug %}" class="btn btn-sm btn-main-action {% if assignment.is_full %}disabled{% endif %}" >
<i class="fas fa-user-plus me-1"></i> {% trans "Submit New Candidate" %}
</a>
{% comment %} <a href="#" class="btn btn-outline-info">
@ -194,7 +194,7 @@
<div class="d-grid gap-2">
{% if assignment.can_submit %}
<a href="{% url 'agency_portal_submit_candidate_page' assignment.slug %}" class="btn btn-main-action">
<a href="{% url 'agency_portal_submit_application_page' assignment.slug %}" class="btn btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit New Candidate" %}
</a>
{% else %}
@ -264,7 +264,7 @@
</div>
</td>
<td>
<a href="{% url 'candidate_application_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary" title="{% trans 'View Profile' %}">
<a href="{% url 'applicant_application_detail' candidate.slug %}" class="btn btn-sm btn-outline-primary" title="{% trans 'View Profile' %}">
<i class="fas fa-eye"></i>
</a>
</td>
@ -523,7 +523,7 @@
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="editCandidateForm" method="post" action="{% url 'agency_portal_edit_candidate' 0 %}">
<form id="editCandidateForm" method="post" action="{% url 'agency_portal_edit_application' 0 %}">
{% csrf_token %}
<input type="hidden" id="edit_candidate_id" name="candidate_id">
<div class="modal-body">
@ -588,7 +588,7 @@
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="deleteCandidateForm" method="post" action="{% url 'agency_portal_delete_candidate' 0 %}">
<form id="deleteCandidateForm" method="post" action="{% url 'agency_portal_delete_application' 0 %}">
{% csrf_token %}
<input type="hidden" id="delete_candidate_id" name="candidate_id">
<div class="modal-body">

View File

@ -49,7 +49,7 @@
</p>
</div>
<div>
{% comment %} <a href="{% url 'agency_portal_submit_candidate' %}" class="btn btn-main-action me-2">
{% comment %} <a href="{% url 'agency_portal_submit_application' %}" class="btn btn-main-action me-2">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit Candidate" %}
</a>
<a href="#" class="btn btn-outline-secondary position-relative">
@ -192,7 +192,7 @@
<div class="d-flex justify-content-between align-items-center">
<div>
{% if stats.can_submit %}
<a href="{% url 'agency_portal_submit_candidate_page' stats.assignment.slug %}"
<a href="{% url 'agency_portal_submit_application_page' stats.assignment.slug %}"
class="btn btn-sm btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Submit Candidate" %}
</a>

View File

@ -235,7 +235,7 @@
{% endif %}
</p>
{% if not search_query and not stage_filter and agency.assignments.exists %}
<a href="{% url 'agency_portal_submit_candidate_page' agency.assignments.first.slug %}"
<a href="{% url 'agency_portal_submit_application_page' agency.assignments.first.slug %}"
class="btn btn-main-action">
<i class="fas fa-user-plus me-1"></i> {% trans "Add First Person" %}
</a>

View File

@ -175,7 +175,7 @@
</h5>
<form method="post" enctype="multipart/form-data" id="candidateForm"
action="{% url 'agency_portal_submit_candidate_page' assignment.slug %}">
action="{% url 'agency_portal_submit_application_page' assignment.slug %}">
{% csrf_token %}
{{form|crispy}}
<button type="submit" class="btn btn-main-action">

View File

@ -184,10 +184,10 @@
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'candidate_portal_dashboard' %}" class=" text-decoration-none text-secondary">{% trans "Dashboard" %}</a>
<a href="{% url 'applicant_portal_dashboard' %}" class=" text-decoration-none text-secondary">{% trans "Dashboard" %}</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'candidate_portal_dashboard' %}#applications" class="text-secondary text-decoration-none">{% trans "My Applications" %}</a>
<a href="{% url 'applicant_portal_dashboard' %}#applications" class="text-secondary text-decoration-none">{% trans "My Applications" %}</a>
</li>
<li class="breadcrumb-item active" aria-current="page" style="
color: #F43B5E; /* Rosy Accent Color */
@ -315,13 +315,13 @@
<div class="row mb-5">
<div class="col-md-6 col-6">
<a href="{% url 'candidate_portal_dashboard' %}" class="text-decoration-none text-dark">
<a href="{% url 'applicant_portal_dashboard' %}" class="text-decoration-none text-dark">
<div class="kaauh-card h-50 shadow-sm action-card">
<div class="card-body text-center mb-4">
<i class="fas fa-arrow-left fa-2x text-primary-theme mb-3"></i>
<h6>{% trans "Go to Dashboard" %}</h6>
<p class="text-muted small">{% trans "View all applications" %}</p>
<a href="{% url 'candidate_portal_dashboard' %}" class="btn btn-main-action btn-sm w-100">
<a href="{% url 'applicant_portal_dashboard' %}" class="btn btn-main-action btn-sm w-100">
{% trans "Dashboard" %}
</a>
</div>

View File

@ -100,7 +100,7 @@
<i class="fas fa-user-plus me-1"></i>
<span class="d-none d-sm-inline">{% trans "Create New Person" %}</span>
</button>
<a href="{% url 'candidate_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
<a href="{% url 'application_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
<i class="fas fa-arrow-left"></i>
<span class="d-none d-sm-inline">{% trans "Back to List" %}</span>
</a>

View File

@ -648,13 +648,13 @@
<div class="card shadow-sm mb-2 p-2">
<h5 class="text-muted mb-3"><i class="fas fa-cog me-2"></i>{% trans "Management Actions" %}</h5>
<div class="d-grid gap-2">
{% comment %} <a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary">
{% comment %} <a href="{% url 'application_update' candidate.slug %}" class="btn btn-outline-primary">
<i class="fas fa-edit"></i> {% trans "Edit Details" %}
</a> {% endcomment %}
{% comment %} <a href="{% url 'candidate_delete' candidate.slug %}" class="btn btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this candidate?" %}')">
{% comment %} <a href="{% url 'application_delete' candidate.slug %}" class="btn btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this candidate?" %}')">
<i class="fas fa-trash-alt"></i> {% trans "Delete Candidate" %}
</a> {% endcomment %}
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary">
<a href="{% url 'application_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> {% trans "Back to List" %}
</a>
{% if candidate.resume %}
@ -669,7 +669,7 @@
{% trans "Download Resume" %}
</a>
{% comment %} <a href="{% url 'candidate_resume_template' candidate.slug %}" class="btn btn-outline-info">
{% comment %} <a href="{% url 'application_resume_template' candidate.slug %}" class="btn btn-outline-info">
<i class="fas fa-file-alt me-1"></i>
{% trans "View Resume AI Overview" %}
</a> {% endcomment %}
@ -711,7 +711,7 @@
</div>
{% else %}
<div style="display: flex; justify-content: center; align-items: center; height: 100%;">
<button type="submit" class="btn btn-sm btn-main-action" hx-get="{% url 'candidate_retry_scoring' candidate.slug %}" hx-select=".resume-parsed-section" hx-target=".resume-parsed-section" hx-swap="outerHTML" hx-on:click="this.disabled=true;this.innerHTML=`Scoring Resume , Please Wait.. <i class='fa-solid fa-spinner fa-spin'></i>`">
<button type="submit" class="btn btn-sm btn-main-action" hx-get="{% url 'application_retry_scoring' candidate.slug %}" hx-select=".resume-parsed-section" hx-target=".resume-parsed-section" hx-swap="outerHTML" hx-on:click="this.disabled=true;this.innerHTML=`Scoring Resume , Please Wait.. <i class='fa-solid fa-spinner fa-spin'></i>`">
<i class="fas fa-redo-alt me-1"></i>
{% trans "Unable to Parse Resume , click to retry" %}
</button>

View File

@ -71,7 +71,7 @@
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<div class="flex space-x-2">
{% if document.file %}
<a href="{% url 'candidate_document_download' document.id %}"
<a href="{% url 'application_document_download' document.id %}"
class="text-green-600 hover:text-green-800 mr-3"
title="Download document">
<i class="fas fa-download"></i>

View File

@ -211,7 +211,7 @@
</h2>
</div>
<div class="d-flex gap-2">
{% comment %} <a href="{% url 'export_candidates_csv' job.slug 'document_review' %}"
{% comment %} <a href="{% url 'export_applications_csv' job.slug 'document_review' %}"
class="btn btn-outline-secondary"
title="{% trans 'Export document review candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -262,7 +262,7 @@
<div class="d-flex align-items-end gap-3">
{# Form 1: Status Update #}
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
{% csrf_token %}
{# Select Input Group - No label needed for this one, so we just flex the select and button #}
@ -290,7 +290,7 @@
data-bs-toggle="modal"
hx-boost='true'
data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}"
hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody"
hx-include="#candidate-form"
title="Email Participants">
@ -300,7 +300,7 @@
</div>
<div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get">
<form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
<table class="table candidate-table align-middle">
<thead>
<tr>
@ -398,7 +398,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="View Profile">
<i class="fas fa-eye ms-1"></i>

View File

@ -178,7 +178,7 @@
</h2>
</div>
<div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'exam' %}"
<a href="{% url 'export_applications_csv' job.slug 'exam' %}"
class="btn btn-outline-secondary"
title="{% trans 'Export exam candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -202,7 +202,7 @@
<div class="kaauh-card shadow-sm p-3">
{% if candidates %}
<div class="bulk-action-bar p-3 bg-light border-bottom">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="action-group">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="action-group">
{% csrf_token %}
{# Using d-flex for horizontal alignment and align-items-end to align items to the bottom baseline #}
@ -233,7 +233,7 @@
data-bs-toggle="modal"
hx-boost='true'
data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}"
hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody"
hx-include="#candidate-form"
title="Email Participants">
@ -304,7 +304,7 @@
<button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
<i class="fas fa-plus"></i>
@ -314,7 +314,7 @@
<button type="button" class="btn btn-{% if candidate.exam_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
{{ candidate.exam_status }}
@ -329,7 +329,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="View Profile">
<i class="fas fa-eye"></i>

View File

@ -202,7 +202,7 @@
title="{% trans 'Sync hired candidates to external sources' %}">
<i class="fas fa-sync me-1"></i> {% trans "Sync to Sources" %}
</button>
<a href="{% url 'export_candidates_csv' job.slug 'hired' %}"
<a href="{% url 'export_applications_csv' job.slug 'hired' %}"
class="btn btn-outline-secondary"
title="{% trans 'Export hired candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -227,7 +227,7 @@
<div class="kaauh-card shadow-sm p-3">
{% if candidates %}
<div class="bulk-action-bar p-3 bg-light border-bottom">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="action-group">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="action-group">
{% csrf_token %}
{# MODIFIED: Using d-flex for horizontal alignment and align-items-end to align everything based on the baseline of the button/select #}
@ -256,7 +256,7 @@
data-bs-toggle="modal"
hx-boost='true'
data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}"
hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody"
hx-include="#candidate-form"
title="Email Participants">
@ -269,7 +269,7 @@
{% endif %}
<div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get">
<form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
{% csrf_token %}
<table class="table candidate-table align-middle">
<thead>
@ -337,12 +337,12 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="View Profile">
<i class="fas fa-eye"></i>
</button>
<a href="{% url 'candidate_resume_template' candidate.slug %}"
<a href="{% url 'application_resume_template' candidate.slug %}"
class="btn btn-outline-primary btn-sm"
title="View Resume Template">
<i class="fas fa-file-alt"></i>
@ -503,7 +503,7 @@
syncButton.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> {% trans "Syncing..." %}';
// Perform sync request
fetch(`{% url 'sync_hired_candidates' job.slug %}`, {
fetch(`{% url 'sync_hired_applications' job.slug %}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',

View File

@ -181,7 +181,7 @@
</h2>
</div>
<div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'interview' %}"
<a href="{% url 'export_applications_csv' job.slug 'interview' %}"
class="btn btn-outline-secondary"
title="{% trans 'Export interview candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -202,7 +202,7 @@
<div class="d-flex align-items-end gap-3">
{# Form 1: Status Update #}
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
{% csrf_token %}
{# Select Input Group - No label needed for this one, so we just flex the select and button #}
@ -239,7 +239,7 @@
data-bs-toggle="modal"
hx-boost='true'
data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}"
hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody"
hx-include="#candidate-form"
title="Email Participants">
@ -251,7 +251,7 @@
</div>
<div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get">
<form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
{% csrf_token %}
<table class="table candidate-table align-middle">
<thead>
@ -288,7 +288,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="View Profile">
{{ candidate.name }}
@ -357,7 +357,7 @@
<button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
<i class="fas fa-plus"></i>
@ -367,7 +367,7 @@
<button type="button" class="btn btn-{% if candidate.interview_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
{{ candidate.interview_status }}
@ -385,7 +385,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'reschedule_meeting_for_candidate' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-get="{% url 'reschedule_meeting_for_application' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-target="#candidateviewModalBody"
title="Reschedule">
<i class="fas fa-redo-alt"></i>
@ -394,7 +394,7 @@
<button type="button" class="btn btn-outline-danger btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'delete_meeting_for_candidate' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-get="{% url 'schedule_meeting_for_application' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-target="#candidateviewModalBody"
title="Delete Meeting">
<i class="fas fa-trash"></i>
@ -413,7 +413,7 @@
<button type="button" class="btn btn-outline-danger btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'delete_onsite_meeting_for_candidate' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-get="{% url 'delete_onsite_meeting_for_application' job.slug candidate.pk candidate.get_latest_meeting.pk %}"
hx-target="#candidateviewModalBody"
title="Delete Meeting">
<i class="fas fa-trash"></i>
@ -425,7 +425,7 @@
<button type="button" class="btn btn-main-action btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'schedule_meeting_for_candidate' job.slug candidate.pk %}"
hx-get="{% url 'schedule_meeting_for_application' job.slug candidate.pk %}"
hx-target="#candidateviewModalBody"
data-modal-title="{% trans 'Schedule Interview' %}"
title="Schedule Interview">
@ -435,7 +435,7 @@
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
{# UPDATED: Points to the specific Onsite scheduling URL #}
hx-get="{% url 'schedule_onsite_meeting_for_candidate' job.slug candidate.pk %}"
hx-get="{% url 'schedule_onsite_meeting_for_application' job.slug candidate.pk %}"
hx-target="#candidateviewModalBody"
data-modal-title="{% trans 'Schedule Onsite Interview' %}"
title="Schedule Onsite Interview">

View File

@ -193,7 +193,7 @@
<h1 style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-users me-2"></i> {% trans "Applications List" %}
</h1>
<a href="{% url 'candidate_create' %}" class="btn btn-main-action">
<a href="{% url 'application_create' %}" class="btn btn-main-action">
<i class="fas fa-plus me-1"></i> {% trans "Add New Application" %}
</a>
</div>
@ -211,7 +211,7 @@
</div>
<div class="col-md-6">
{% url 'candidate_list' as candidate_list_url %}
{% url 'application_list' as candidate_list_url %}
<form method="GET" class="row g-3 align-items-end h-100">
{% if search_query %}<input type="hidden" name="q" value="{{ search_query }}">{% endif %}
@ -250,7 +250,7 @@
<i class="fas fa-filter me-1"></i> {% trans "Apply Filters" %}
</button>
{% if job_filter or stage_filter or search_query %}
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary btn-sm">
<a href="{% url 'application_list' %}" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-times me-1"></i> {% trans "Clear" %}
</a>
{% endif %}
@ -286,7 +286,7 @@
<tbody>
{% for candidate in applications %}
<tr>
<td class="fw-medium"><a href="{% url 'candidate_detail' candidate.slug %}" class="text-decoration-none link-secondary">{{ candidate.name }}<a></td>
<td class="fw-medium"><a href="{% url 'application_detail' candidate.slug %}" class="text-decoration-none link-secondary">{{ candidate.name }}<a></td>
<td>{{ candidate.email }}</td>
<td> <span class="badge bg-primary"><a href="{% url 'job_detail' candidate.job.slug %}" class="text-decoration-none text-white">{{ candidate.job.title }}</a></span></td>
<td>
@ -297,7 +297,7 @@
</span>
{% endif %}
{% else %}
<a href="{% url 'candidate_list' %}" class="text-decoration-none d-flex align-items-center gap-2">
<a href="{% url 'application_list' %}" class="text-decoration-none d-flex align-items-center gap-2">
<svg class="kaats-spinner" viewBox="0 0 50 50" style="width: 25px; height: 25px;">
<circle cx="25" cy="25" r="20"></circle>
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"
@ -325,16 +325,16 @@
<td>{{ candidate.created_at|date:"d-m-Y" }}</td>
<td class="text-end">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'View' %}">
<a href="{% url 'application_detail' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'View' %}">
<i class="fas fa-eye"></i>
</a>
{% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<a href="{% url 'application_update' candidate.slug %}" class="btn btn-outline-secondary" title="{% trans 'Edit' %}">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-danger" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i>
</button>
@ -356,7 +356,7 @@
<div class="card-body d-flex flex-column">
<div class="d-flex justify-content-between align-items-start mb-3">
<h5 class="card-title flex-grow-1 me-3">
<a href="{% url 'candidate_detail' candidate.slug %}" class="text-decoration-none text-primary-theme ">{{ candidate.name }}</a>
<a href="{% url 'application_detail' candidate.slug %}" class="text-decoration-none text-primary-theme ">{{ candidate.name }}</a>
</h5>
<span class="badge bg-primary">{{ candidate.stage }}</span>
</div>
@ -379,16 +379,16 @@
<div class="mt-auto pt-3 border-top">
<div class="d-flex gap-2">
<a href="{% url 'candidate_detail' candidate.slug %}" class="btn btn-sm btn-main-action">
<a href="{% url 'application_detail' candidate.slug %}" class="btn btn-sm btn-main-action">
<i class="fas fa-eye"></i> {% trans "View" %}
</a>
{% if user.is_staff %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary">
<a href="{% url 'application_update' candidate.slug %}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-edit"></i> {% trans "Edit" %}
</a>
<button type="button" class="btn btn-outline-danger btn-sm" title="{% trans 'Delete' %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"
data-delete-url="{% url 'candidate_delete' candidate.slug %}"
data-delete-url="{% url 'application_delete' candidate.slug %}"
data-item-name="{{ candidate.name }}">
<i class="fas fa-trash-alt"></i>
</button>
@ -411,7 +411,7 @@
<h3>{% trans "No application found" %}</h3>
<p class="text-muted">{% trans "Create your first application." %}</p>
{% if user.is_staff %}
<a href="{% url 'candidate_create' %}" class="btn btn-main-action mt-3">
<a href="{% url 'application_create' %}" class="btn btn-main-action mt-3">
<i class="fas fa-plus me-1"></i> {% trans "Add Application" %}
</a>
{% endif %}

View File

@ -180,7 +180,7 @@
</h2>
</div>
<div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'offer' %}"
<a href="{% url 'export_applications_csv' job.slug 'offer' %}"
class="btn btn-outline-secondary"
title="{% trans 'Export offer candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -201,7 +201,7 @@
<div class="d-flex align-items-end gap-3">
{# Form: Hired/Rejected Status Update #}
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="d-flex align-items-end gap-2 action-group">
{% csrf_token %}
{# Select element #}
@ -236,7 +236,7 @@
data-bs-toggle="modal"
hx-boost='true'
data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}"
hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody"
hx-include="#candidate-form"
title="Email Participants">
@ -247,7 +247,7 @@
</div>
{% endif %}
<div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="get">
<form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="get">
{% csrf_token %}
<table class="table candidate-table align-middle">
<thead>
@ -293,7 +293,7 @@
<button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
<i class="fas fa-plus"></i>
@ -303,7 +303,7 @@
<button type="button" class="btn btn-{% if candidate.offer_status == 'Accepted' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
{{ candidate.offer_status }}
@ -361,7 +361,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="View Profile">
<i class="fas fa-eye"></i>

View File

@ -184,7 +184,7 @@
{% endif %}
</td>
<td>
<a href="{% url 'candidate_application_detail' application.slug %}"
<a href="{% url 'applicant_application_detail' application.slug %}"
class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye me-1"></i>
{% trans "View Details" %}

View File

@ -492,7 +492,7 @@
<div class="d-flex align-items-start mb-3">
<div class="flex-grow-1">
<h5 class="card-title fw-bold mb-1">
<a href="{% url 'candidate_application_detail' application.slug %}"
<a href="{% url 'applicant_application_detail' application.slug %}"
class="text-decoration-none text-primary-theme hover:text-primary-theme-dark">
{{ application.job.title }}
</a>
@ -524,7 +524,7 @@
<!-- Action Button -->
<div class="mt-auto">
<a href="{% url 'candidate_application_detail' application.slug %}"
<a href="{% url 'applicant_application_detail' application.slug %}"
class="btn btn-main-action w-100 rounded-pill">
<i class="fas fa-eye me-2"></i> {% trans "View Details" %}
</a>
@ -568,7 +568,7 @@
<div class="d-flex align-items-center">
<span class="text-muted small me-3">{% trans "Uploaded:" %} {{ document.uploaded_at|date:"d M Y" }}</span>
<a href="{{ document.file.url }}" target="_blank" class="btn btn-sm btn-outline-secondary me-2"><i class="fas fa-eye"></i></a>
<a href="{% url 'candidate_document_delete' document.id %}" class="btn btn-sm btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this document?" %}')"><i class="fas fa-trash-alt"></i></a>
<a href="{% url 'application_document_delete' document.id %}" class="btn btn-sm btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this document?" %}')"><i class="fas fa-trash-alt"></i></a>
</div>
</li>
{% empty %}

View File

@ -224,7 +224,7 @@
</h2>
</div>
<div class="d-flex gap-2">
<a href="{% url 'export_candidates_csv' job.slug 'screening' %}"
<a href="{% url 'export_applications_csv' job.slug 'screening' %}"
class="btn btn-outline-secondary"
title="{% trans 'Export screening candidates to CSV' %}">
<i class="fas fa-download me-1"></i> {% trans "Export CSV" %}
@ -319,7 +319,7 @@
<div class="kaauh-card p-3">
{% if candidates %}
<div class="bulk-action-bar p-3 bg-light border-bottom">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post" class="action-group">
<form hx-boost="true" hx-include="#candidate-form" action="{% url 'application_update_status' job.slug %}" method="post" class="action-group">
{% csrf_token %}
{# MODIFIED: Using d-flex for horizontal alignment and align-items-end to align everything based on the baseline of the button/select #}
@ -348,7 +348,7 @@
data-bs-toggle="modal"
hx-boost='true'
data-bs-target="#emailModal"
hx-get="{% url 'compose_candidate_email' job.slug %}"
hx-get="{% url 'compose_application_email' job.slug %}"
hx-target="#emailModalBody"
hx-include="#candidate-form"
title="Email Participants">
@ -361,7 +361,7 @@
{% endif %}
<div class="table-responsive">
<form id="candidate-form" action="{% url 'candidate_update_status' job.slug %}" method="post">
<form id="candidate-form" action="{% url 'application_update_status' job.slug %}" method="post">
{% csrf_token %}
<table class="table candidate-table align-middle">
<thead>
@ -471,7 +471,7 @@
<button type="button" class="btn btn-outline-secondary btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="View Candidate Profile and Criteria">
<i class="fas fa-eye"></i>

View File

@ -94,12 +94,12 @@
<p class="text-white opacity-75 mb-0">{% trans "Edit candidate information and details" %}</p>
</div>
<div class="d-flex gap-2 mt-1">
<a href="{% url 'candidate_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
<a href="{% url 'application_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
<i class="fas fa-arrow-left"></i>
<span class="d-none d-sm-inline">{% trans "Back to List" %}</span>
</a>
{% if object.slug %}
<a href="{% url 'candidate_detail' object.slug %}" class="btn btn-outline-light btn-sm" title="{% trans 'View Candidate' %}">
<a href="{% url 'application_detail' object.slug %}" class="btn btn-outline-light btn-sm" title="{% trans 'View Candidate' %}">
<i class="fas fa-eye"></i>
<span class="d-none d-sm-inline">{% trans "View" %}</span>
</a>

View File

@ -59,7 +59,7 @@
<button type="button" class="btn btn-main-action"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'candidate_criteria_view_htmx' candidate.pk %}"
hx-get="{% url 'application_criteria_view_htmx' candidate.pk %}"
hx-target="#candidateviewModalBody"
title="{% trans 'View Details and Score Breakdown' %}">
<i class="fas fa-eye"></i>

View File

@ -60,7 +60,7 @@
</li>
<li style="display: flex; align-items: center;">
<a
href="{% url 'candidate_list' %}"
href="{% url 'application_list' %}"
style="
color: #6c757d; /* text-secondary/gray */
text-decoration: none;
@ -82,7 +82,7 @@
</li>
<li style="display: flex; align-items: center;">
<a
href="{% url 'candidate_detail' candidate.slug %}"
href="{% url 'application_detail' candidate.slug %}"
style="
color: #6c757d; /* text-secondary/gray */
text-decoration: none;

View File

@ -3,7 +3,7 @@
<button type="button" class="btn btn-{% if candidate.exam_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'exam' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
{{ candidate.exam_status }}

View File

@ -3,7 +3,7 @@
<button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
<i class="fas fa-plus"></i>
@ -13,7 +13,7 @@
<button type="button" class="btn btn-{% if candidate.interview_status == 'Passed' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'interview' 'passed' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
{{ candidate.interview_status }}

View File

@ -3,7 +3,7 @@
<button type="button" class="btn btn-warning btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Accepted' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Accepted' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
<i class="fas fa-plus"></i>
@ -13,7 +13,7 @@
<button type="button" class="btn btn-{% if candidate.offer_status == 'Accepted' %}success{% else %}danger{% endif %} btn-sm"
data-bs-toggle="modal"
data-bs-target="#candidateviewModal"
hx-get="{% url 'update_candidate_status' job.slug candidate.slug 'offer' 'Rejected' %}"
hx-get="{% url 'update_application_status' job.slug candidate.slug 'offer' 'Rejected' %}"
hx-target="#candidateviewModalBody"
title="Pass Exam">
{{ candidate.offer_status }}

View File

@ -1,5 +1,5 @@
<!-- Stage Update Form with Errors -->
<form id="stageUpdateForm" hx-post="{% url 'candidate_update_stage' candidate.slug %}">
<form id="stageUpdateForm" hx-post="{% url 'application_update_stage' candidate.slug %}">
{% csrf_token %}
<!-- Stage Selection -->

View File

@ -23,12 +23,12 @@
<!-- Form Container -->
<div id="stageUpdateFormContainer">
<form id="stageUpdateForm" action="{% url 'candidate_update_stage' candidate.slug %}" method="post">
<form id="stageUpdateForm" action="{% url 'application_update_stage' candidate.slug %}" method="post">
{% csrf_token %}
<!-- Stage Selection -->
<div class="mb-3">
<label for="id_stage" class="form-label">
<i class="fas fa-arrow-right me-1"></i>Move to Stage
<i class="fas fa-arrow-right me-1"></i>{% trans "Move to Stage" %}
</label>
<select id="id_stage" name="stage" class="form-select">
@ -42,19 +42,19 @@
<div class="alert alert-light border" id="availableStagesInfo">
<small class="text-muted">
<i class="fas fa-lightbulb me-1"></i>
<span id="availableStagesText">Select a stage above to see transition information.</span>
<span id="availableStagesText">{% trans "Select a stage above to see transition information." %}</span>
</small>
</div>
<!-- Form Actions -->
<div class="d-flex justify-content-between mt-4">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-1"></i>Cancel
<i class="fas fa-times me-1"></i>{% trans "Cancel" %}
</button>
<button type="submit" class="btn btn-main-action" id="stageUpdateSubmit">
<i class="fas fa-save me-1"></i>
<span class="ms-2">Update</span>
<span class="ms-2">{% trans "Update" %}</span>
</button>
</div>
</form>

View File

@ -23,7 +23,7 @@
</div>
{% endif %}
</div>
<a href="{% url 'candidate_interview_view' job.slug %}" class="btn btn-outline-secondary">
<a href="{% url 'applications_interview_view' job.slug %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Candidates" %}
</a>
</div>
@ -85,7 +85,7 @@
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i> {% trans "Schedule Meeting" %}
</button>
<a href="{% url 'candidate_interview_view' job.slug %}" class="btn btn-secondary">
<a href="{% url 'applications_interview_view' job.slug %}" class="btn btn-secondary">
<i class="fas fa-times me-1"></i> {% trans "Cancel" %}
</a>
</div>