small update

This commit is contained in:
ismail 2025-11-30 14:08:55 +03:00
parent b158cb3e7b
commit f45e9b75c4
7 changed files with 51 additions and 185 deletions

View File

@ -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) ---

View File

@ -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"""

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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" %}

View File

@ -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>