Files
ihrm/recruitment/views.py
Nikhil Ravi Cybrosys 09b2137792 [UPDT]candidate update stage && [FIX] typo in notification (#8)
* [UPDT]candidate update stage

* [FIX]typo in notification - email sent

---------

Co-authored-by: NIKHIL RAVI <nikhil@cybrosys.com>
2023-05-23 16:37:11 +05:30

1094 lines
43 KiB
Python
Executable File

from django.shortcuts import render, redirect
from .models import Recruitment, Candidate, Stage
from horilla.decorators import permission_required, login_required, hx_request_required
from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
from employee.models import Employee
from recruitment.forms import RecruitmentCreationForm, CandidateCreationForm, StageCreationForm, ApplicationForm, RecruitmentDropDownForm, StageDropDownForm, CandidateDropDownForm, StageNoteForm
from django.contrib.auth.models import User, Permission, Group
from django.core import serializers
from django.contrib import messages
from django.views.decorators.http import require_http_methods
from django.core.paginator import Paginator
from recruitment.filters import CandidateFilter, RecruitmentFilter, StageFilter
from django.views.decorators.http import require_http_methods
from django.forms import formset_factory
from recruitment.filters import RecruitmentFilter
from recruitment.models import StageNote
import json
from django.core.mail import send_mail
from horilla import settings
from django.db.models import Q
from recruitment.methods import is_recruitmentmanager, is_stagemanager, recruitment_manages, stage_manages
from base.methods import sortby
from recruitment.decorators import manager_can_enter, recruitment_manager_can_enter
from notifications.signals import notify
from django.utils.translation import gettext_lazy as _
# Create your views here.
def is_stagemanager(request, stage_id=False):
"""
This method is used to identify the employee is a stage manager or not, if stage_id is passed through args, method will
check the employee is manager to the corresponding stage, return tuple with boolean and all stages that employee is manager.
if called this method without stage_id args it will return boolean with all the stage that the employee is stage manager
Args:
request : django http request
stage_id : stage instance id
"""
user = request.user
employee = user.employee_get
if not stage_id:
return (employee.stage_set.exists() or user.is_superuser, employee.stage_set.all())
stage = Stage.objects.get(id=stage_id)
return employee in stage.stage_managers.all() or user.is_superuser or is_recruitmentmanager(request, rec_id=stage.recruitment_id.id)[0], employee.stage_set.all()
def is_recruitmentmanager(request, rec_id=False):
"""
This method is used to identify the employee is a recruitment manager or not, if rec_id is passed through args, method will
check the employee is manager to the corresponding recruitment, return tuple with boolean and all recruitment that employee is manager.
if called this method without recruitment args it will return boolean with all the recruitment that the employee is recruitment manager
Args:
request : django http request
rec_id : recruitment instance id
"""
user = request.user
employee = user.employee_get
if not rec_id:
return employee.recruitment_set.exists() or user.is_superuser, employee.recruitment_set.all()
recruitment = Recruitment.objects.get(id=rec_id)
return employee in recruitment.recruitment_managers.all() or user.is_superuser, employee.recruitment_set.all()
def stages_create(recruitment: object):
"""
This method is used to create some default stages when create recruitment
Args:
id : recruitment instance
"""
new_stage = Stage.objects.create(
recruitment_id=recruitment,
stage='New',
sequence=1,
stage_type='initial'
)
interview_stage = Stage.objects.create(
recruitment_id=recruitment,
stage='Interview',
sequence=2,
stage_type='interview'
)
hired_stage = Stage.objects.create(
recruitment_id=recruitment,
stage='Hired',
sequence=3,
stage_type='hired'
)
return
def paginator_qry(qryset, page_number):
"""
This method is used to generate common paginator limit.
"""
paginator = Paginator(qryset, 50)
qryset = paginator.get_page(page_number)
return qryset
@login_required
@permission_required('recruitment.add_recruitment')
def recruitment(request):
"""
This method is used to create recruitment, when create recruitment this method
add recruitment view,create candidate, change stage sequence and so on, some of
the permission is checking manually instead of using django permission permission
to the recruitment managers
"""
form = RecruitmentCreationForm()
if request.method == 'POST':
form = RecruitmentCreationForm(request.POST)
if form.is_valid():
recruitment = form.save()
messages.success(request, _('Recruitment added.'))
try:
managers = recruitment.recruitment_managers.select_related(
'employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users, verb="You are chosen as one of recruitment manager",
icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
response = render(
request, 'recruitment/recruitment_form.html', {'form': form})
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
return render(request, 'recruitment/recruitment_form.html', {'form': form})
@login_required
@permission_required('recruitment.change_recruitment')
@require_http_methods(['POST'])
def remove_recruitment_manager(request, mid, rid):
"""
This method is used to remove selected manager from the recruitment,
when remove the manager permissions also removed if the employee is not
exists in more stage manager or recruitment manager
Args:
mid : employee manager_id in the recruitment
rid : recruitment_id
"""
recruitment = Recruitment.objects.get(id=rid)
manager = Employee.objects.get(id=mid)
recruitment.recruitment_managers.remove(manager)
messages.success(request, _('Recruitment manager removed successfully.'))
notify.send(request.user.employee_get, recipient=manager.employee_user_id,
verb=f"You are removed from recruitment manager from {recruitment}", icon="person-remove", redirect="")
recruitment = Recruitment.objects.all()
previous_data = request.environ['QUERY_STRING']
return render(request, 'recruitment/recruitment_component.html', {'data': paginator_qry(recruitment, request.GET.get('page')), 'pd': previous_data})
@login_required
@permission_required('recruitment.view_recruitment')
def recruitment_view(request):
"""
This method is used to render all recruitment to view
"""
if not request.GET:
request.GET.copy().update({'is_active': 'on'})
form = RecruitmentCreationForm()
filter = RecruitmentFilter(request.GET, queryset=Recruitment.objects.all())
return render(request, 'recruitment/recruitment_view.html', {'data': paginator_qry(filter.qs, request.GET.get('page')), 'f': filter, 'form': form})
@login_required
@permission_required('recruitment.view_recruitment')
def recruitment_search(request):
"""
This method is used to search recruitment
"""
filter = RecruitmentFilter(request.GET)
previous_data = request.environ['QUERY_STRING']
recruitment = sortby(request, filter.qs, 'orderby')
return render(request, 'recruitment/recruitment_component.html', {
'data': paginator_qry(recruitment, request.GET.get('page')),
'pd': previous_data})
@login_required
@permission_required('recruitment.change_recruitment')
@hx_request_required
def recruitment_update(request, id):
"""
This method is used to update the recruitment, when updating the recruitment,
any changes in manager is exists then permissions also assigned to the manager
Args:
id : recruitment_id
"""
recruitment = Recruitment.objects.get(id=id)
form = RecruitmentCreationForm(instance=recruitment)
if request.method == 'POST':
form = RecruitmentCreationForm(
request.POST, instance=recruitment)
if form.is_valid():
recruitment = form.save()
messages.success(request, _('Recruitment Updated.'))
response = render(
request, 'recruitment/recruitment_form.html', {'form': form})
try:
managers = recruitment.recruitment_managers.select_related(
'employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"{recruitment} is updated, You are chosen as one of managers", icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
return render(request, 'recruitment/recruitment_update_form.html', {'form': form})
@login_required
@permission_required('recruitment.delete_recruitment')
@require_http_methods(['POST'])
def recruitment_delete(request, id):
"""
This method is used to permanently delete the recruitment
Args:
id : recruitment_id
"""
recruitment = Recruitment.objects.get(id=id)
recruitment_mangers = recruitment.recruitment_managers.all()
all_stage_permissions = Permission.objects.filter(
content_type__app_label='recruitment', content_type__model='stage')
all_candidate_permissions = Permission.objects.filter(
content_type__app_label='recruitment', content_type__model='candidate')
for manager in recruitment_mangers:
all_this_manger = manager.recruitment_set.all()
if len(all_this_manger) == 1:
for stage_permission in all_candidate_permissions:
manager.employee_user_id.user_permissions.remove(
stage_permission.id)
for candidate_permission in all_stage_permissions:
manager.employee_user_id.user_permissions.remove(
candidate_permission.id)
try:
recruitment.delete()
messages.success(request, _('Recruitment deleted successfully.'))
except Exception as e:
messages.error(request, e)
messages.error(request, _("You cannot delete this recruitment"))
recruitment = Recruitment.objects.all()
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
@login_required
@manager_can_enter('recruitment.view_recruitment')
def recruitment_pipeline(request):
"""
This method is used to filter out candidate through pipeline structure
"""
view = request.GET.get('view')
template = 'pipeline/pipeline.html'
if view == 'card':
template = 'pipeline/pipeline_card.html'
recruitment_form = RecruitmentDropDownForm()
stage_form = StageDropDownForm()
candidate_form = CandidateDropDownForm()
recruitment = Recruitment.objects.filter(is_active=True, closed=False)
if request.method == 'POST':
if request.POST.get('recruitment_managers') is not None and request.user.has_perm('add_recruitment'):
recruitment_form = RecruitmentDropDownForm(request.POST)
if recruitment_form.is_valid():
recruitment = recruitment_form.save()
recruitment_form = RecruitmentDropDownForm()
messages.success(request, _('Recruitment added.'))
try:
managers = recruitment.recruitment_managers.select_related(
'employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"You are chosen as recruitment manager for the recruitment {recruitment}", icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
elif request.FILES.get('resume') is not None:
if request.user.has_perm('add_candidate') or is_stagemanager(request,):
candidate_form = CandidateDropDownForm(
request.POST, request.FILES)
if candidate_form.is_valid():
candidate = candidate_form.save()
candidate_form = CandidateDropDownForm()
try:
managers = candidate.stage_id.stage_managers.select_related(
'employee_user_id')
users = [
employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"New candidate arrived on stage {stage.stage}", icon="person-add", redirect="/recruitment/pipeline")
except Exception as e:
pass
messages.success(request, _('Candidate added.'))
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
elif request.POST.get('stage_managers') and request.user.has_perm('add_stage'):
stage_form = StageDropDownForm(request.POST)
if stage_form.is_valid():
if recruitment_manages(request, stage_form.instance.recruitment_id) or request.user.has_perm('recruitment.add_stage'):
stage = stage_form.save()
stage_form = StageDropDownForm()
messages.success(request, _('Stage added.'))
try:
managers = stage.stage_managers.select_related(
'employee_user_id')
users = [
employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"You are chosen as a stage manager on the stage {stage.stage} in recruitment {stage.recruitment_id}", icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
messages.info(request, _('You dont have access'))
return render(request, template, {'recruitment': recruitment, 'recruitment_form': recruitment_form, 'stage_form': stage_form, 'candidate_form': candidate_form})
@login_required
@permission_required('recruitment.view_recruitment')
def recruitment_pipeline_card(request):
"""
This method is used to render pipeline card structure.
"""
search = request.GET.get('search')
search = search if search != None else ''
recruitment = Recruitment.objects.all()
candidates = Candidate.objects.filter(
name__icontains=search, is_active=True)
stages = Stage.objects.all()
return render(request, 'pipeline/pipeline_components/pipeline_card_view.html', {'recruitment': recruitment, 'candidates': candidates, 'stages': stages})
@login_required
@permission_required('recruitment.view_candidate')
def pipeline_candidate_search(request):
"""
This method is used to search candidate
"""
search = request.GET['search']
template = 'pipeline/pipeline_components/kanban_tabs.html'
if request.GET.get('view') == 'card':
template = 'pipeline/pipeline_components/kanban_tabs.html'
return render(request, template)
@login_required
@recruitment_manager_can_enter('recruitment.change_stage')
def stage_update_pipeline(request, id):
"""
This method is used to update stage from pipeline view
"""
stage = Stage.objects.get(id=id)
form = StageCreationForm(instance=stage)
if request.POST:
form = StageCreationForm(request.POST, instance=stage)
if form.is_valid():
stage = form.save()
messages.success(request, _('Stage updated.'))
try:
managers = stage.stage_managers.select_related(
'employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"{stage.stage} stage in recruitment {stage.recruitment_id} is updated, You are chosen as one of managers", icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
return render(request, 'pipeline/form/stage_update.html', {'form': form})
@login_required
@recruitment_manager_can_enter('recruitment.change_recruitment')
def recruitment_update_pipeline(request, id):
"""
This method is used to update recruitment from pipeline view
"""
recruitment = Recruitment.objects.get(id=id)
form = RecruitmentCreationForm(instance=recruitment)
if request.POST:
form = RecruitmentCreationForm(request.POST, instance=recruitment)
if form.is_valid():
recruitment = form.save()
messages.success(request, _('Recruitment updated.'))
try:
managers = recruitment.recruitment_managers.select_related(
'employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"{recruitment} is updated, You are chosen as one of managers", icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
return render(request, 'pipeline/form/recruitment_update.html', {'form': form})
@login_required
@permission_required('recruitment.delete_recruitment')
@require_http_methods(['POST'])
def recruitment_delete_pipeline(request, id):
recruitment = Recruitment.objects.get(id=id)
try:
recruitment.delete()
messages.success(request, _('Recruitment deleted.'))
except Exception as e:
messages.error(request, e)
messages.error(request, _('Recruitment already in use.'))
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
@login_required
@manager_can_enter('recruitment.change_candidate')
def candidate_stage_update(request, id):
"""
This method is a ajax method used to update candidate stage when drag and drop
the candidate from one stage to another on the pipeline template
Args:
id : candidate_id
"""
stage_id = request.POST['stageId']
candidate = Candidate.objects.get(id=id)
candidate_history = candidate.candidate_history.all().first()
stage = Stage.objects.get(id=stage_id)
previous_stage = candidate_history.stage_id
if previous_stage == stage:
return JsonResponse({'type': 'info', 'message': _('No change detected.')})
"""
Here set the last updated schedule date on this stage if schedule exists in history
"""
candidate_history = candidate.candidate_history.filter(stage_id=stage)
schedule_date = None
if candidate_history.exists():
# this condition is executed when a candidate dropped back to any previous
# stage, if there any scheduled date then set it back
schedule_date = candidate_history.first().schedule_date
stage_manager_on_this_recruitment = is_stagemanager(
request)[1].filter(recruitment_id=stage.recruitment_id).exists()
if stage_manager_on_this_recruitment or request.user.is_superuser or is_recruitmentmanager(rec_id=stage.recruitment_id.id)[0]:
candidate.stage_id = stage
candidate.schedule_date = None
candidate.hired = False
candidate.schedule_date = schedule_date
candidate.start_onboard = False
if stage.stage_type == 'hired':
candidate.hired = True
candidate.save()
try:
managers = stage.stage_managers.select_related('employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"New candidate arrived on stage {stage.stage}", icon="person-add", redirect="/recruitment/pipeline")
except Exception as e:
pass
return JsonResponse({'type': 'success', 'message': _('Candidate stage updated')})
@login_required
@hx_request_required
@manager_can_enter('recruitment.add_stagenote')
def add_note(request, id=None):
"""
This method renders template component to add candidate remark
"""
form = StageNoteForm(initial={'candidate_id': id})
if request.method == 'POST':
form = StageNoteForm(request.POST,)
if form.is_valid():
note = form.save(commit=False)
note.stage_id = note.candidate_id.stage_id
note.updated_by = request.user.employee_get
note.save()
messages.success(request, _('Note added successfully..'))
response = render(
request, 'pipeline/pipeline_components/add_note.html', {'form': form})
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
return render(request, 'pipeline/pipeline_components/add_note.html', {'note_form': form, })
@login_required
@hx_request_required
@manager_can_enter('recruitment.view_stagenote')
def view_note(request, id):
"""
This method renders a template components to view candidate remark or note
Args:
id : candidate instance id
"""
candidate = Candidate.objects.get(id=id)
return render(request, 'pipeline/pipeline_components/view_note.html', {'cand': candidate})
@login_required
@permission_required('recruitment.change_stagenote')
def note_update(request, id):
"""
This method is used to update the stage not
Args:
id : stage note instance id
"""
note = StageNote.objects.get(id=id)
form = StageNoteForm(instance=note)
if request.POST:
form = StageNoteForm(request.POST, instance=note)
if form.is_valid():
form.save()
messages.success(request, _('Note updated successfully...'))
response = render(
request, 'pipeline/pipeline_components/update_note.html', {'form': form})
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
return render(request, 'pipeline/pipeline_components/update_note.html', {'form': form})
@login_required
@permission_required('recruitment.delete_stagenote')
def note_delete(request, id):
"""
This method is used to delete the stage note
"""
note = StageNote.objects.get(id=id)
candidate = note.candidate_id
try:
note.delete()
messages.success(request, _('Note deleted'))
except Exception as e:
messages.error(request, e)
messages.error(request, _('You cannot delete this note.'))
return render(request, 'pipeline/pipeline_components/view_note.html', {'cand': candidate})
@login_required
@require_http_methods(['DELETE'])
@permission_required('recruitment.delete_stagenote')
def candidate_remark_delete(request, id):
"""
This method is used to delete the candidate stage note
Args:
id : stage note instance id
"""
stage_note = StageNote.objects.get(id=id)
candidate = stage_note.candidate_note_id.candidate_id
try:
stage_note.delete()
messages.success(request, _('Note deleted'))
except Exception as e:
messages.error(request, e)
messages.error(request, _('You cannot delete this note.'))
return render(request, 'pipeline/pipeline_components/candidate_remark_view.html', {'cand': candidate})
@login_required
@permission_required('recruitment.change_candidate')
def candidate_schedule_date_update(request):
"""
This is a an ajax method to update schedule date for a candidate
"""
candidate_id = request.POST['candidateId']
schedule_date = request.POST['date']
candidate = Candidate.objects.get(id=candidate_id)
candidate.schedule_date = schedule_date
candidate.save()
return JsonResponse({'message': 'congratulations'})
@login_required
@permission_required('recruitment.add_stage')
def stage(request):
"""
This method is used to create stages, also several permission assigned to the stage managers
"""
form = StageCreationForm()
if request.method == 'POST':
form = StageCreationForm(request.POST)
if form.is_valid():
stage = form.save()
recruitment = stage.recruitment_id
rec_stages = Stage.objects.filter(
recruitment_id=recruitment, is_active=True).order_by('sequence').last()
if rec_stages.sequence is None:
stage.sequence = 1
else:
stage.sequence = rec_stages.sequence + 1
stage.save()
messages.success(request, _('Stage added.'))
try:
managers = stage.stage_managers.select_related(
'employee_user_id')
users = [employee.employee_user_id for employee in managers]
notify.send(request.user.employee_get, recipient=users,
verb=f"Stage {stage} is updated on recruitment {stage.recruitment_id}, You are chosen as one of managers", icon="people-circle", redirect="/recruitment/pipeline")
except Exception as e:
pass
response = render(request, 'stage/stage_form.html', {'form': form})
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
return render(request, 'stage/stage_form.html', {'form': form})
@login_required
@permission_required('recruitment.view_stage')
def stage_view(request):
"""
This method is used to render all stages to a template
"""
stages = Stage.objects.filter()
filter = StageFilter()
form = StageCreationForm()
return render(request, 'stage/stage_view.html', {
'data': paginator_qry(stages, request.GET.get('page')), 'form': form,
'f': filter})
@login_required
@permission_required('recruitment.view_stage')
def stage_search(request):
"""
This method is used to search stage
"""
stages = StageFilter(request.GET).qs
previous_data = request.environ['QUERY_STRING']
stages = sortby(request, stages, 'orderby')
return render(request, 'stage/stage_component.html', {'data': paginator_qry(stages, request.GET.get('page')), 'pd': previous_data})
@login_required
@permission_required('recruitment.change_stage')
def remove_stage_manager(request, mid, sid):
"""
This method is used to remove selected stage manager and also removing the given
permission if the employee is not exists in more stage manager or recruitment manager
Args:
mid : manager_id in the stage
sid : stage_id
"""
stage = Stage.objects.get(id=sid)
manager = Employee.objects.get(id=mid)
notify.send(request.user.employee_get, recipient=manager.employee_user_id,
verb=f"You are removed from stage managers from stage {stage}", icon="person-remove", redirect="")
stage.stage_managers.remove(manager)
messages.success(request, _('Stage manager removed successfully.'))
stages = Stage.objects.all()
previous_data = request.environ['QUERY_STRING']
return render(request, 'stage/stage_component.html', {'data': paginator_qry(stages, request.GET.get('page')), 'pd': previous_data})
@login_required
@require_http_methods(['POST'])
@permission_required('recruitment.change_stage')
def stage_sequence_update(request):
"""
This is also a ajax method used to update sequence of stage while drag and drop stage in pipeline template,
"""
stages = json.loads(json.loads(request.POST['stages']))
sequences = json.loads(request.POST['newSequences'])
# for index,stage_id in enumerate(stages):
# stage = Stage.objects.get(id=stage_id)
# stage.sequence = sequences[index]
# stage.save()
return JsonResponse({'message': 'Congratulations'})
@login_required
@permission_required('recruitment.change_stage')
@hx_request_required
def stage_update(request, id):
"""
This method is used to update stage, if the managers changed then permission assigned to new managers also
Args:
id : stage_id
"""
stages = Stage.objects.get(id=id)
form = StageCreationForm(instance=stages)
if request.method == 'POST':
form = StageCreationForm(request.POST, instance=stages)
if form.is_valid():
stage = form.save()
messages.success(request, _('Stage updated.'))
response = render(
request, 'recruitment/recruitment_form.html', {'form': form})
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
return render(request, 'stage/stage_update_form.html', {'form': form})
@login_required
@require_http_methods(['POST'])
@hx_request_required
def stage_name_update(request, id):
"""
This method is used to update the name of recruitment stage
"""
stage = Stage.objects.get(id=id)
stage.stage = request.POST['stage']
stage.save()
return HttpResponse({'message': 'success'})
@login_required
@permission_required('recruitment.delete_stage')
@require_http_methods(['POST', 'DELETE'])
def stage_delete(request, id):
"""
This method is used to delete stage permanently
Args:
id : stage_id
"""
stage = Stage.objects.get(id=id)
stage_managers = stage.stage_managers.all()
for manager in stage_managers:
all_this_manger = manager.stage_set.all()
if len(all_this_manger) == 1:
view_recruitment = Permission.objects.get(
codename='view_recruitment')
manager.employee_user_id.user_permissions.remove(
view_recruitment.id)
initial_stage_manager = all_this_manger.filter(stage_type='initial')
if len(initial_stage_manager) == 1:
add_candidate = Permission.objects.get(codename='add_candidate')
change_candidate = Permission.objects.get(
codename='change_candidate')
manager.employee_user_id.user_permissions.remove(add_candidate.id)
manager.employee_user_id.user_permissions.remove(
change_candidate.id)
stage.stage_managers.remove(manager)
try:
stage.delete()
messages.success(request, _('Stage deleted successfully.'))
except Exception as e:
messages.error(request, e)
messages.error(request, _('You cannot delete this stage'))
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
@login_required
@permission_required('recruitment.add_candidate')
def candidate(request):
"""
This method used to create candidate
"""
form = CandidateCreationForm()
open_recruitment = Recruitment.objects.filter(closed=False, is_active=True)
if request.method == 'POST':
form = CandidateCreationForm(request.POST, request.FILES)
if form.is_valid():
candidate = form.save(commit=False)
candidate.start_onboard = False
if candidate.stage_id is None:
candidate.stage_id = Stage.objects.filter(
recruitment_id=candidate.recruitment_id, stage_type="initial").first()
candidate.save()
messages.success(request, _('Candidate added.'))
return redirect('/recruitment/candidate-view')
return render(request, 'candidate/candidate_create_form.html', {'form': form, 'open_recruitment': open_recruitment})
@login_required
@permission_required('recruitment.add_candidate')
def recruitment_stage_get(request, id):
"""
This method returns all stages as json
Args:
id: recruitment_id
"""
recruitment = Recruitment.objects.get(id=id)
all_stages = recruitment.stage_set.all()
all_stage_json = serializers.serialize('json', all_stages)
return JsonResponse({'stages': all_stage_json})
@login_required
@permission_required('recruitment.view_candidate')
def candidate_view(request):
"""
This method render all candidate to the template
"""
previous_data = request.environ['QUERY_STRING']
candidates = Candidate.objects.filter(is_active=True)
filter = CandidateFilter(queryset=candidates)
return render(request, 'candidate/candidate_view.html', {
'data': paginator_qry(filter.qs, request.GET.get('page')),
'pd': previous_data,
'f': filter
})
@login_required
@permission_required('recruitment.view_candidate')
def candidate_filter_view(request):
"""
This method is used for filter,pagination and search candidate.
"""
previous_data = request.environ['QUERY_STRING']
filter = CandidateFilter(
request.GET, queryset=Candidate.objects.filter(is_active=True))
paginator = Paginator(filter.qs, 24)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'candidate/candidate_card.html', {'data': page_obj, 'pd': previous_data})
@login_required
@permission_required('recruitment.view_candidate')
def candidate_search(request):
"""
This method is used to search candidate model and return matching objects
"""
previous_data = request.environ['QUERY_STRING']
search = request.GET.get('search')
if search is None:
search = ''
candidates = Candidate.objects.filter(name__icontains=search)
candidates = CandidateFilter(request.GET, queryset=candidates).qs
template = 'candidate/candidate_card.html'
if request.GET.get('view') == 'list':
template = 'candidate/candidate_list.html'
candidates = sortby(request, candidates, 'orderby')
candidates = paginator_qry(candidates, request.GET.get('page'))
return render(request, template, {'data': candidates, 'pd': previous_data})
@login_required
@permission_required('recruitment.view_candidate')
def candidate_view_list(request):
"""
This method renders all candidate on candidate_list.html template
"""
previous_data = request.environ['QUERY_STRING']
candidates = Candidate.objects.all()
if request.GET.get('is_active') is None:
candidates = candidates.filter(is_active=True)
candidates = CandidateFilter(request.GET, queryset=candidates).qs
return render(request, 'candidate/candidate_list.html', {
'data': paginator_qry(candidates, request.GET.get('page')),
'pd': previous_data}
)
@login_required
@permission_required('recruitment.view_candidate')
def candidate_view_card(request):
"""
This method renders all candidate on candidate_card.html template
"""
previous_data = request.environ['QUERY_STRING']
candidates = Candidate.objects.all()
if request.GET.get('is_active') is None:
candidates = candidates.filter(is_active=True)
candidates = CandidateFilter(request.GET, queryset=candidates).qs
return render(request, 'candidate/candidate_card.html', {'data': paginator_qry(candidates, request.GET.get('page')), 'pd': previous_data})
@login_required
@permission_required('recruitment.view_candidate')
def candidate_view_individual(request, id):
"""
This method is used to view profile of candidate.
"""
candidate = Candidate.objects.get(id=id)
return render(request, 'candidate/individual.html', {'candidate': candidate})
@login_required
@manager_can_enter('recruitment.change_candidate')
def candidate_update(request, id):
"""
Used to update or change the candidate
Args:
id : candidate_id
"""
candidate = Candidate.objects.get(id=id)
form = CandidateCreationForm(instance=candidate)
if request.method == 'POST':
form = CandidateCreationForm(
request.POST, request.FILES, instance=candidate)
if form.is_valid():
candidate = form.save()
if candidate.stage_id is None:
candidate.stage_id = Stage.objects.filter(
recruitment_id=candidate.recruitment_id, stage_type="initial").first()
if candidate.stage_id.recruitment_id != candidate.recruitment_id:
candidate.stage_id = candidate.recruitment_id.stage_set.filter(stage_type="initial").first()
candidate.save()
messages.success(request, _('Candidate Updated Successfully.'))
return redirect('/recruitment/candidate-view')
return render(request, 'candidate/candidate_create_form.html', {'form': form})
@login_required
@permission_required('recruitment.delete_candidate')
@require_http_methods(['DELETE', 'POST'])
def candidate_delete(request, id):
"""
This method is used to delete candidate permanently
Args:
id : candidate_id
"""
try:
Candidate.objects.get(id=id).delete()
messages.success(request, _('Candidate deleted successfully.'))
except Exception as e:
messages.error(request, e)
messages.error(request, _('You cannot delete this candidate'))
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
@login_required
@permission_required('recruitment.delete_candidate')
def candidate_archive(request, id):
"""
This method is used to archive or un-archive candidates
"""
candidate = Candidate.objects.get(id=id)
candidate.is_active = not candidate.is_active
candidate.save()
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
@login_required
@permission_required('recruitment.delete_candidate')
@require_http_methods(['POST'])
def candidate_bulk_delete(request):
"""
This method is used to bulk delete candidates
"""
ids = request.POST['ids']
ids = json.loads(ids)
for id in ids:
candidate = Candidate.objects.get(id=id)
try:
candidate.delete()
messages.success(request, _('%(candidate)s deleted.') % {'candidate':candidate})
except Exception as e:
messages.error(request, _('You cannot delete %(candidate)s') % {'candidate':candidate})
messages.error(request, e)
return JsonResponse({'message': 'Success'})
@login_required
@permission_required('recruitment.delete_candidate')
@require_http_methods(['POST'])
def candidate_bulk_archive(request):
"""
This method is used to archive/un-archive bulk candidates
"""
ids = request.POST['ids']
ids = json.loads(ids)
is_active = True
message = 'un-archived'
if request.GET.get('is_active') == 'False':
is_active = False
message = 'archived'
for id in ids:
candidate = Candidate.objects.get(id=id)
candidate.is_active = is_active
candidate.save()
messages.success(request, f'{candidate} is {message}')
return JsonResponse({'message': 'Success'})
@login_required
@permission_required('recruitment.view_history')
def candidate_history(request, id):
"""
This method is used to view candidate stage changes
Args:
id : candidate_id
"""
candidate = Candidate.objects.get(id=id)
candidate_history = candidate.history.all()
return render(request, 'candidate/candidate_history.html', {'history': candidate_history})
def application_form(request):
"""
This method renders candidate form to create candidate"""
form = ApplicationForm()
if request.POST:
form = ApplicationForm(request.POST, request.FILES)
if form.is_valid():
candidate = form.save(commit=False)
recruitment = candidate.recruitment_id
stages = recruitment.stage_set.all()
if stages.filter(stage_type='initial').exists():
candidate.stage_id = stages.filter(
stage_type='initial').first()
else:
candidate.stage_id = stages.order_by('sequence').first()
candidate.save()
messages.success(request, _('Application saved.'))
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
return render(request, 'candidate/application_form.html', {'form': form})
@login_required
@hx_request_required
@manager_can_enter('recruitment.change_candidate')
def form_send_mail(request, id):
"""
This method is used to render the bootstrap modal content body form
"""
candidate = Candidate.objects.get(id=id)
return render(request, 'pipeline/pipeline_components/send_mail.html', {'cand': candidate})
@login_required
@manager_can_enter('recruitment.change_candidate')
def send_acknowledgement(request):
"""
This method is used to send acknowledgement mail to the candidate
"""
try:
to = request.POST.get('to')
subject = request.POST.get('subject')
bdy = request.POST.get('body')
res = send_mail(subject, bdy, settings.EMAIL_HOST_USER,
[to], fail_silently=False)
if (res == 1):
return HttpResponse("""
<div class="oh-alert-container">
<div class="oh-alert oh-alert--animated oh-alert--success">
Mail send.
</div>
</div>
""")
except:
pass
return HttpResponse("""
<div class="oh-alert-container">
<div class="oh-alert oh-alert--animated oh-alert--danger">
Sorry, Something went wrong.
</div>
</div>
"""
)
@login_required
@manager_can_enter('view.recruitment')
def dashboard(request):
"""
This method is used to render individual dashboard for recruitment module
"""
candidates = Candidate.objects.all()
hired_candidates = candidates.filter(hired=True)
total_candidates = len(candidates)
total_hired_candidates = len(hired_candidates)
hire_ratio = 0
if total_candidates != 0:
hire_ratio = "%.1f" % ((total_hired_candidates/total_candidates)*100)
return render(request, 'dashboard/dashboard.html', {
'total_candidates': total_candidates,
'total_hired_candidates': total_hired_candidates,
'hire_ratio': hire_ratio,
'onboard_candidates': hired_candidates.filter(start_onboard=True),
})
def stage_type_candidate_count(rec, type):
"""
This method is used find the count of candidate in recruitment
"""
candidates_count = 0
for stage in rec.stage_set.filter(stage_type=type):
candidates_count = candidates_count + \
len(stage.candidate_set.filter(is_active=True))
return candidates_count
@login_required
@manager_can_enter('view.recruitment')
def dashboard_pipeline(request):
"""
This method is used generate recruitment dataset for the dashboard
"""
recruitment = Recruitment.objects.filter(closed=False)
data_set = []
labels = [type[1] for type in Stage.stage_types]
for rec in recruitment:
data = [stage_type_candidate_count(
rec, type[0]) for type in Stage.stage_types]
data_set.append({
'label': rec.__str__(),
'data': data,
})
return JsonResponse({'dataSet': data_set, 'labels': labels})