small update
This commit is contained in:
parent
b158cb3e7b
commit
f45e9b75c4
@ -572,11 +572,12 @@ urlpatterns = [
|
||||
path('interviews/', views.interview_list, name='interview_list'),
|
||||
path('interviews/<slug:slug>/', views.interview_detail, name='interview_detail'),
|
||||
path('interviews/<slug:slug>/update_interview_status', views.update_interview_status, name='update_interview_status'),
|
||||
path('interviews/<slug:slug>/cancel_interview_for_application', views.cancel_interview_for_application, name='cancel_interview_for_application'),
|
||||
|
||||
# Interview Creation URLs
|
||||
path('interviews/create/<slug:candidate_slug>/', views.interview_create_type_selection, name='interview_create_type_selection'),
|
||||
path('interviews/create/<slug:candidate_slug>/remote/', views.interview_create_remote, name='interview_create_remote'),
|
||||
path('interviews/create/<slug:candidate_slug>/onsite/', views.interview_create_onsite, name='interview_create_onsite'),
|
||||
path('interviews/create/<slug:application_slug>/', views.interview_create_type_selection, name='interview_create_type_selection'),
|
||||
path('interviews/create/<slug:application_slug>/remote/', views.interview_create_remote, name='interview_create_remote'),
|
||||
path('interviews/create/<slug:application_slug>/onsite/', views.interview_create_onsite, name='interview_create_onsite'),
|
||||
path('interviews/<slug:job_slug>/get_interview_list', views.get_interview_list, name='get_interview_list'),
|
||||
|
||||
# # --- SCHEDULED INTERVIEW URLS (New Centralized Management) ---
|
||||
|
||||
@ -5184,30 +5184,21 @@ def portal_logout(request):
|
||||
|
||||
# Interview Creation Views
|
||||
@staff_user_required
|
||||
def interview_create_type_selection(request, candidate_slug):
|
||||
"""Show interview type selection page for a candidate"""
|
||||
candidate = get_object_or_404(Application, slug=candidate_slug)
|
||||
# Validate candidate is in Interview stage
|
||||
# if candidate.stage != 'Interview':
|
||||
# messages.error(request, f"Candidate {candidate.name} is not in Interview stage.")
|
||||
# return redirect('candidate_interview_view', slug=candidate.job.slug)
|
||||
def interview_create_type_selection(request, application_slug):
|
||||
"""Show interview type selection page for a application"""
|
||||
application = get_object_or_404(Application, slug=application_slug)
|
||||
|
||||
context = {
|
||||
'candidate': candidate,
|
||||
'job': candidate.job,
|
||||
'application': application,
|
||||
'job': application.job,
|
||||
}
|
||||
return render(request, 'interviews/interview_create_type_selection.html', context)
|
||||
|
||||
|
||||
@staff_user_required
|
||||
def interview_create_remote(request, candidate_slug):
|
||||
def interview_create_remote(request, application_slug):
|
||||
"""Create remote interview for a candidate"""
|
||||
application = get_object_or_404(Application, slug=candidate_slug)
|
||||
|
||||
# Validate candidate is in Interview stage
|
||||
# if candidate.stage != 'Interview':
|
||||
# messages.error(request, f"Candidate {candidate.name} is not in Interview stage.")
|
||||
# return redirect('candidate_interview_view', slug=candidate.job.slug)
|
||||
application = get_object_or_404(Application, slug=application_slug)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = RemoteInterviewForm(request.POST)
|
||||
@ -5220,41 +5211,16 @@ def interview_create_remote(request, candidate_slug):
|
||||
"recruitment.tasks.create_interview_and_meeting",
|
||||
application.pk, application.job.pk, schedule.pk, schedule.interview_date,schedule.interview_time, form.cleaned_data['duration']
|
||||
)
|
||||
# interview.interview_type = 'REMOTE'
|
||||
# interview.status = 'SCHEDULED'
|
||||
# interview.save()
|
||||
|
||||
# Create ZoomMeetingDetails record
|
||||
# from .models import ZoomMeetingDetails
|
||||
# zoom_meeting = ZoomMeetingDetails.objects.create(
|
||||
# topic=form.cleaned_data['topic'],
|
||||
# start_time=timezone.make_aware(
|
||||
# timezone.datetime.combine(
|
||||
# form.cleaned_data['interview_date'],
|
||||
# form.cleaned_data['interview_time']
|
||||
# ),
|
||||
# timezone.get_current_timezone()
|
||||
# ),
|
||||
# duration=form.cleaned_data['duration'],
|
||||
# meeting_id=f"KAUH-{interview.id}-{timezone.now().timestamp()}",
|
||||
# join_url=f"https://zoom.us/j/{interview.id}",
|
||||
# password=secrets.token_urlsafe(16),
|
||||
# status='scheduled'
|
||||
# )
|
||||
|
||||
# Link Zoom meeting to interview
|
||||
# interview.interview_location = zoom_meeting
|
||||
# interview.save()
|
||||
|
||||
messages.success(request, f"Remote interview scheduled for {application.name}")
|
||||
return redirect('interview_list')
|
||||
return redirect('interview_detail', slug=schedule.slug)
|
||||
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error creating remote interview: {str(e)}")
|
||||
form = RemoteInterviewForm()
|
||||
form.initial['topic'] = f"Interview for {application.job.title} - {application.name}"
|
||||
context = {
|
||||
'candidate': application,
|
||||
'application': application,
|
||||
'job': application.job,
|
||||
'form': form,
|
||||
}
|
||||
@ -5262,14 +5228,9 @@ def interview_create_remote(request, candidate_slug):
|
||||
|
||||
|
||||
@staff_user_required
|
||||
def interview_create_onsite(request, candidate_slug):
|
||||
def interview_create_onsite(request, application_slug):
|
||||
"""Create onsite interview for a candidate"""
|
||||
candidate = get_object_or_404(Application, slug=candidate_slug)
|
||||
|
||||
# Validate candidate is in Interview stage
|
||||
# if candidate.stage != 'Interview':
|
||||
# messages.error(request, f"Candidate {candidate.name} is not in Interview stage.")
|
||||
# return redirect('candidate_interview_view', slug=candidate.job.slug)
|
||||
application = get_object_or_404(Application, slug=application_slug)
|
||||
|
||||
if request.method == 'POST':
|
||||
from .models import Interview
|
||||
@ -5283,48 +5244,22 @@ def interview_create_onsite(request, candidate_slug):
|
||||
physical_address=form.cleaned_data["physical_address"],
|
||||
duration=form.cleaned_data["duration"],location_type="Onsite",status="SCHEDULED")
|
||||
|
||||
schedule = ScheduledInterview.objects.create(application=candidate,job=candidate.job,interview=interview,interview_date=form.cleaned_data["interview_date"],interview_time=form.cleaned_data["interview_time"])
|
||||
# Create ScheduledInterview record
|
||||
# interview = form.save(commit=False)
|
||||
# interview.interview_type = 'ONSITE'
|
||||
# interview.status = 'SCHEDULED'
|
||||
# interview.save()
|
||||
schedule = ScheduledInterview.objects.create(application=application,job=application.job,interview=interview,interview_date=form.cleaned_data["interview_date"],interview_time=form.cleaned_data["interview_time"])
|
||||
|
||||
# Create OnsiteLocationDetails record
|
||||
# from .models import OnsiteLocationDetails
|
||||
# onsite_location = OnsiteLocationDetails.objects.create(
|
||||
# topic=form.cleaned_data['topic'],
|
||||
# start_time=timezone.make_aware(
|
||||
# timezone.datetime.combine(
|
||||
# form.cleaned_data['interview_date'],
|
||||
# form.cleaned_data['interview_time']
|
||||
# ),
|
||||
# timezone.get_current_timezone()
|
||||
# ),
|
||||
# duration=form.cleaned_data['duration'],
|
||||
# physical_address=form.cleaned_data['physical_address'],
|
||||
# room_number=form.cleaned_data.get('room_number', ''),
|
||||
# location_type='ONSITE',
|
||||
# status='scheduled'
|
||||
# )
|
||||
|
||||
# # Link onsite location to interview
|
||||
# interview.interview_location = onsite_location
|
||||
# interview.save()
|
||||
|
||||
messages.success(request, f"Onsite interview scheduled for {candidate.name}")
|
||||
messages.success(request, f"Onsite interview scheduled for {application.name}")
|
||||
return redirect('interview_detail', slug=schedule.slug)
|
||||
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error creating onsite interview: {str(e)}")
|
||||
else:
|
||||
# Pre-populate topic
|
||||
form.initial['topic'] = f"Interview for {candidate.job.title} - {candidate.name}"
|
||||
form.initial['topic'] = f"Interview for {application.job.title} - {application.name}"
|
||||
|
||||
form = OnsiteInterviewForm()
|
||||
form.initial['topic'] = f"Interview for {application.job.title} - {application.name}"
|
||||
context = {
|
||||
'candidate': candidate,
|
||||
'job': candidate.job,
|
||||
'application': application,
|
||||
'job': application.job,
|
||||
'form': form,
|
||||
}
|
||||
return render(request, 'interviews/interview_create_onsite.html', context)
|
||||
@ -5350,6 +5285,21 @@ def update_interview_status(request,slug):
|
||||
messages.success(request, "Interview status updated successfully.")
|
||||
return redirect('interview_detail', slug=slug)
|
||||
|
||||
@require_POST
|
||||
def cancel_interview_for_application(request,slug):
|
||||
scheduled_interview = get_object_or_404(ScheduledInterview, slug=slug)
|
||||
if request.method == 'POST':
|
||||
if scheduled_interview.interview_type == 'REMOTE':
|
||||
result = delete_zoom_meeting(scheduled_interview.interview.meeting_id)
|
||||
if result["status"] != "success":
|
||||
messages.error(request, f"Error cancelling Zoom meeting: {result.get('message', 'Unknown error')}")
|
||||
return redirect('interview_detail', slug=slug)
|
||||
|
||||
scheduled_interview.delete()
|
||||
messages.success(request, "Interview cancelled successfully.")
|
||||
return redirect('interview_list')
|
||||
|
||||
|
||||
@login_required
|
||||
def agency_access_link_deactivate(request, slug):
|
||||
"""Deactivate an agency access link"""
|
||||
|
||||
@ -10,9 +10,9 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="fas fa-building me-2"></i>
|
||||
Create Onsite Interview for {{ candidate.name }}
|
||||
Create Onsite Interview for {{ application.name }}
|
||||
</h4>
|
||||
<a href="{% url 'interview_create_type_selection' candidate.slug %}"
|
||||
<a href="{% url 'interview_create_type_selection' application.slug %}"
|
||||
class="btn btn-outline-primary">
|
||||
<i class="fas fa-arrow-left me-2"></i>
|
||||
Back to Candidate List
|
||||
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">
|
||||
Schedule an onsite interview for <strong>{{ candidate.name }}</strong>
|
||||
Schedule an onsite interview for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.
|
||||
</p>
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{% url 'interview_create_onsite' candidate_slug=candidate.slug %}">
|
||||
<form method="post" action="{% url 'interview_create_onsite' application.slug %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row">
|
||||
@ -99,35 +99,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% comment %} <div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.interviewer.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-user me-1"></i>
|
||||
Interviewer
|
||||
</label>
|
||||
{{ form.interviewer }}
|
||||
{% if form.interviewer.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.interviewer.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div> {% endcomment %}
|
||||
</div>
|
||||
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="{{ form.topic.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-comment me-1"></i>
|
||||
Meeting Topic
|
||||
</label>
|
||||
{{ form.topic }}
|
||||
{% if form.topic.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.topic.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> {% endcomment %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.physical_address.id_for_label }}" class="form-label">
|
||||
@ -158,48 +130,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% comment %} <div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="{{ form.floor_number.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-layer-group me-1"></i>
|
||||
Floor Number
|
||||
</label>
|
||||
{{ form.floor_number }}
|
||||
{% if form.floor_number.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.floor_number.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div> {% endcomment %}
|
||||
{% comment %} </div> {% endcomment %}
|
||||
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="{{ form.parking_info.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-parking me-1"></i>
|
||||
Parking Information
|
||||
</label>
|
||||
{{ form.parking_info }}
|
||||
{% if form.parking_info.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.parking_info.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> {% endcomment %}
|
||||
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="{{ form.notes.id_for_label }}" class="form-label">
|
||||
<i class="fas fa-sticky-note me-1"></i>
|
||||
Notes
|
||||
</label>
|
||||
{{ form.notes }}
|
||||
{% if form.notes.errors %}
|
||||
<div class="text-danger small">
|
||||
{{ form.notes.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> {% endcomment %}
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="submit" class="btn btn-main-action">
|
||||
<i class="fas fa-save me-2"></i>
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="fas fa-video me-2"></i>
|
||||
Create Remote Interview for {{ candidate.name }}
|
||||
Create Remote Interview for {{ application.name }}
|
||||
</h4>
|
||||
<a href="{% url 'interview_create_type_selection' candidate.slug %}"
|
||||
<a href="{% url 'interview_create_type_selection' application.slug %}"
|
||||
class="btn btn-outline-primary">
|
||||
<i class="fas fa-arrow-left me-2"></i>
|
||||
Back to Candidate List
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">
|
||||
Schedule a remote interview for <strong>{{ candidate.name }}</strong>
|
||||
Schedule a remote interview for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.
|
||||
</p>
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{% url 'interview_create_remote' candidate_slug=candidate.slug %}">
|
||||
<form method="post" action="{% url 'interview_create_remote' application.slug %}">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
<div class="d-flex justify-content-between">
|
||||
|
||||
@ -10,17 +10,17 @@
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">
|
||||
<i class="fas fa-calendar-plus me-2"></i>
|
||||
Create Interview for {{ candidate.name }}
|
||||
Create Interview for {{ application.name }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body" hx-boost="true" hx-push-url="false" hx-select=".card-body" hx-swap="innerHTML" hx-target="#candidateviewModalBody">
|
||||
<p class="text-muted mb-3">
|
||||
Select the type of interview you want to schedule for <strong>{{ candidate.name }}</strong>
|
||||
Select the type of interview you want to schedule for <strong>{{ application.name }}</strong>
|
||||
for the position of <strong>{{ job.title }}</strong>.
|
||||
</p>
|
||||
|
||||
<div class="d-grid gap-3" style="grid-template-columns: 1fr 1fr;">
|
||||
<a href="{% url 'interview_create_remote' candidate_slug=candidate.slug %}"
|
||||
<a href="{% url 'interview_create_remote' application.slug %}"
|
||||
class="btn btn-outline-primary btn-lg h-100 p-3 text-decoration-none">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-video me-2"></i>
|
||||
@ -29,7 +29,7 @@
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'interview_create_onsite' candidate_slug=candidate.slug %}"
|
||||
<a href="{% url 'interview_create_onsite' application.slug %}"
|
||||
class="btn btn-outline-primary btn-lg h-100 p-3 text-decoration-none">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-building me-2"></i>
|
||||
|
||||
@ -690,17 +690,12 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="#">
|
||||
<form method="post" action="{% url 'cancel_interview_for_application' interview.slug %}">
|
||||
{% csrf_token %}
|
||||
<div class="alert alert-warning">
|
||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
||||
{% trans "Are you sure you want to cancel this interview? This action cannot be undone." %}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cancel_reason" class="form-label">{% trans "Reason for Cancellation" %}</label>
|
||||
<textarea class="form-control" id="cancel_reason" name="reason" rows="3" required
|
||||
placeholder="{% trans 'Please provide a reason for cancellation' %}"></textarea>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-danger btn-sm">
|
||||
<i class="fas fa-times me-1"></i> {% trans "Cancel Interview" %}
|
||||
|
||||
@ -434,12 +434,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{% comment %} <a href="{% url 'interview_create_type_selection' candidate_slug=candidate.slug %}"
|
||||
class="btn btn-main-action btn-sm"
|
||||
title="Schedule Interview">
|
||||
<i class="fas fa-calendar-plus me-1"></i>
|
||||
Schedule
|
||||
</a> {% endcomment %}
|
||||
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#candidateviewModal"
|
||||
@ -450,12 +445,7 @@
|
||||
<i class="fas fa-calendar-plus me-1"></i>
|
||||
Schedule Interview
|
||||
</button>
|
||||
{% comment %} <a href="{% url 'interview_create_type_selection' candidate_slug=candidate.slug %}"
|
||||
class="btn btn-main-action btn-sm"
|
||||
title="Schedule Interview">
|
||||
<i class="fas fa-calendar-plus me-1"></i>
|
||||
Schedule
|
||||
</a> {% endcomment %}
|
||||
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user