Files
ihrm/recruitment/forms.py

1103 lines
34 KiB
Python
Raw Normal View History

"""
forms.py
This module contains the form classes used in the application.
Each form represents a specific functionality or data input in the
application. They are responsible for validating
and processing user input data.
Classes:
- YourForm: Represents a form for handling specific data input.
Usage:
2023-05-10 15:06:57 +05:30
from django import forms
class YourForm(forms.Form):
field_name = forms.CharField()
def clean_field_name(self):
# Custom validation logic goes here
pass
"""
import logging
import uuid
from ast import Dict
from datetime import date, datetime
from typing import Any
from django import forms
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from base.forms import Form
from base.methods import reload_queryset
from employee.filters import EmployeeFilter
from employee.models import Employee
from horilla import horilla_middlewares
from horilla_widgets.widgets.horilla_multi_select_field import HorillaMultiSelectField
from horilla_widgets.widgets.select_widgets import HorillaMultiSelectWidget
from leave.models import LeaveRequest
from recruitment import widgets
from recruitment.models import (
Candidate,
InterviewSchedule,
JobPosition,
Recruitment,
RecruitmentMailTemplate,
RecruitmentSurvey,
RejectedCandidate,
RejectReason,
SkillZone,
SkillZoneCandidate,
Stage,
StageFiles,
StageNote,
SurveyTemplate,
)
logger = logging.getLogger(__name__)
2023-05-10 15:06:57 +05:30
class ModelForm(forms.ModelForm):
"""
Overriding django default model form to apply some styles
"""
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
request = getattr(horilla_middlewares._thread_locals, "request", None)
2023-12-01 15:36:51 +05:30
reload_queryset(self.fields)
2023-05-10 15:06:57 +05:30
for field_name, field in self.fields.items():
widget = field.widget
if isinstance(widget, (forms.DateInput)):
field.initial = date.today()
if isinstance(
widget,
(forms.NumberInput, forms.EmailInput, forms.TextInput, forms.FileInput),
):
label = _(field.label)
2023-05-10 15:06:57 +05:30
field.widget.attrs.update(
{"class": "oh-input w-100", "placeholder": label}
)
2023-05-10 15:06:57 +05:30
elif isinstance(widget, forms.URLInput):
field.widget.attrs.update(
{"class": "oh-input w-100", "placeholder": field.label}
)
2023-05-10 15:06:57 +05:30
elif isinstance(widget, (forms.Select,)):
field.empty_label = _("---Choose {label}---").format(
label=_(field.label)
)
2023-05-10 15:06:57 +05:30
self.fields[field_name].widget.attrs.update(
{
"id": uuid.uuid4,
"class": "oh-select oh-select-2 w-100",
"style": "height:50px;",
}
)
2023-05-10 15:06:57 +05:30
elif isinstance(widget, (forms.Textarea)):
label = _(field.label)
2023-05-10 15:06:57 +05:30
field.widget.attrs.update(
{
"class": "oh-input w-100",
"placeholder": label,
"rows": 2,
"cols": 40,
}
)
elif isinstance(
widget,
(
forms.CheckboxInput,
forms.CheckboxSelectMultiple,
),
):
field.widget.attrs.update({"class": "oh-switch__checkbox "})
2023-05-10 15:06:57 +05:30
try:
self.fields["employee_id"].initial = request.user.employee_get
except:
pass
try:
self.fields["company_id"].initial = (
request.user.employee_get.get_company
)
except:
pass
2023-05-10 15:06:57 +05:30
class RegistrationForm(forms.ModelForm):
"""
Overriding django default model form to apply some styles
"""
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
2023-12-01 15:36:51 +05:30
reload_queryset(self.fields)
2023-05-10 15:06:57 +05:30
for field_name, field in self.fields.items():
widget = field.widget
if isinstance(widget, (forms.Select,)):
label = ""
2023-05-10 15:06:57 +05:30
if field.label is not None:
label = _(field.label)
field.empty_label = _("---Choose {label}---").format(label=label)
2023-05-10 15:06:57 +05:30
self.fields[field_name].widget.attrs.update(
{"id": uuid.uuid4, "class": "oh-select-2 oh-select--sm w-100"}
)
2023-05-10 15:06:57 +05:30
elif isinstance(widget, (forms.TextInput)):
field.widget.attrs.update(
{
"class": "oh-input w-100",
}
)
elif isinstance(
widget,
(
forms.CheckboxInput,
forms.CheckboxSelectMultiple,
),
):
field.widget.attrs.update({"class": "oh-switch__checkbox "})
2023-05-10 15:06:57 +05:30
class DropDownForm(forms.ModelForm):
"""
Overriding django default model form to apply some styles
"""
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
2023-12-01 15:36:51 +05:30
reload_queryset(self.fields)
2023-05-10 15:06:57 +05:30
for field_name, field in self.fields.items():
widget = field.widget
if isinstance(
widget,
(
forms.NumberInput,
forms.EmailInput,
forms.TextInput,
forms.FileInput,
forms.URLInput,
),
):
if field.label is not None:
label = _(field.label)
field.widget.attrs.update(
{
"class": "oh-input oh-input--small oh-table__add-new-row d-block w-100",
"placeholder": label,
}
)
2023-05-10 15:06:57 +05:30
elif isinstance(widget, (forms.Select,)):
self.fields[field_name].widget.attrs.update(
{
"class": "oh-select-2 oh-select--xs-forced ",
"id": uuid.uuid4(),
}
)
2023-05-10 15:06:57 +05:30
elif isinstance(widget, (forms.Textarea)):
if field.label is not None:
label = _(field.label)
field.widget.attrs.update(
{
"class": "oh-input oh-input--small oh-input--textarea",
"placeholder": label,
"rows": 1,
"cols": 40,
}
)
elif isinstance(
widget,
(
forms.CheckboxInput,
forms.CheckboxSelectMultiple,
),
):
field.widget.attrs.update({"class": "oh-switch__checkbox "})
2023-05-10 15:06:57 +05:30
class RecruitmentCreationForm(ModelForm):
"""
Form for Recruitment model
"""
# survey_templates = forms.ModelMultipleChoiceField(
# queryset=SurveyTemplate.objects.all(),
# widget=forms.SelectMultiple(),
# label=_("Survey Templates"),
# required=False,
# )
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = Recruitment
fields = "__all__"
exclude = ["is_active"]
2023-05-10 15:06:57 +05:30
widgets = {
"start_date": forms.DateInput(attrs={"type": "date"}),
"end_date": forms.DateInput(attrs={"type": "date"}),
"description": forms.Textarea(attrs={"data-summernote": ""}),
2023-05-10 15:06:57 +05:30
}
labels = {"description": _("Description"), "vacancy": _("Vacancy")}
2023-05-10 15:06:57 +05:30
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("attendance_form.html", context)
return table_html
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
reload_queryset(self.fields)
if not self.instance.pk:
self.fields["recruitment_managers"] = HorillaMultiSelectField(
queryset=Employee.objects.filter(is_active=True),
widget=HorillaMultiSelectWidget(
filter_route_name="employee-widget-filter",
filter_class=EmployeeFilter,
filter_instance_contex_name="f",
filter_template_path="employee_filters.html",
required=True,
),
label="Employee",
)
def clean(self):
if isinstance(self.fields["recruitment_managers"], HorillaMultiSelectField):
ids = self.data.getlist("recruitment_managers")
if ids:
self.errors.pop("recruitment_managers", None)
super().clean()
2023-05-10 15:06:57 +05:30
class StageCreationForm(ModelForm):
"""
Form for Stage model
"""
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = Stage
fields = "__all__"
exclude = ["sequence", "is_active"]
2023-05-10 15:06:57 +05:30
labels = {
"stage": _("Stage"),
2023-05-10 15:06:57 +05:30
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
reload_queryset(self.fields)
if not self.instance.pk:
self.fields["stage_managers"] = HorillaMultiSelectField(
queryset=Employee.objects.filter(is_active=True),
widget=HorillaMultiSelectWidget(
filter_route_name="employee-widget-filter",
filter_class=EmployeeFilter,
filter_instance_contex_name="f",
filter_template_path="employee_filters.html",
required=True,
),
label="Employee",
)
def clean(self):
if isinstance(self.fields["stage_managers"], HorillaMultiSelectField):
ids = self.data.getlist("stage_managers")
if ids:
self.errors.pop("stage_managers", None)
super().clean()
2023-05-10 15:06:57 +05:30
class CandidateCreationForm(ModelForm):
"""
Form for Candidate model
"""
load = forms.CharField(widget=widgets.RecruitmentAjaxWidget, required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.recruitment_id is not None:
if self.instance is not None:
self.fields["job_position_id"] = forms.ModelChoiceField(
queryset=self.instance.recruitment_id.open_positions.all(),
# additional field options
)
self.fields["recruitment_id"].widget.attrs = {"data-widget": "ajax-widget"}
self.fields["job_position_id"].widget.attrs = {"data-widget": "ajax-widget"}
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = Candidate
fields = "__all__"
exclude = [
"confirmation",
"scheduled_for",
"schedule_date",
"joining_date",
2023-08-01 16:49:33 +05:30
"sequence",
"stage_id",
"offerletter_status",
]
2023-05-10 15:06:57 +05:30
widgets = {
"scheduled_date": forms.DateInput(attrs={"type": "date"}),
"dob": forms.DateInput(attrs={"type": "date"}),
2023-05-10 15:06:57 +05:30
}
labels = {
"name": _("Name"),
"email": _("Email"),
"mobile": _("Mobile"),
"address": _("Address"),
"zip": _("Zip"),
2023-05-10 15:06:57 +05:30
}
def save(self, commit: bool = ...):
candidate = self.instance
recruitment = candidate.recruitment_id
stage = candidate.stage_id
candidate.hired = False
candidate.start_onboard = False
if stage is not None:
if stage.stage_type == "hired" and candidate.canceled is False:
2023-05-10 15:06:57 +05:30
candidate.hired = True
candidate.start_onboard = True
candidate.recruitment_id = recruitment
candidate.stage_id = stage
job_id = self.data.get("job_position_id")
if job_id:
job_position = JobPosition.objects.get(id=job_id)
self.instance.job_position_id = job_position
2023-05-10 15:06:57 +05:30
return super().save(commit)
def clean(self):
if self.instance.name is not None:
self.errors.pop("job_position_id", None)
if (
self.instance.job_position_id is None
or self.data.get("job_position_id") == ""
):
raise forms.ValidationError(
{"job_position_id": "This field is required"}
)
if (
self.instance.job_position_id
not in self.instance.recruitment_id.open_positions.all()
):
raise forms.ValidationError({"job_position_id": "Choose valid choice"})
return super().clean()
2023-05-10 15:06:57 +05:30
class ApplicationForm(RegistrationForm):
"""
Form for create Candidate
"""
load = forms.CharField(widget=widgets.RecruitmentAjaxWidget, required=False)
active_recruitment = Recruitment.objects.filter(
is_active=True, closed=False, is_published=True
)
2023-05-10 15:06:57 +05:30
recruitment_id = forms.ModelChoiceField(queryset=active_recruitment)
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = Candidate
exclude = (
"stage_id",
"schedule_date",
"referral",
"start_onboard",
"hired",
"is_active",
"canceled",
"joining_date",
2023-08-01 16:49:33 +05:30
"sequence",
"offerletter_status",
"source",
2023-05-10 15:06:57 +05:30
)
widgets = {
"recruitment_id": forms.TextInput(
attrs={
"required": "required",
}
),
"dob": forms.DateInput(
attrs={
"type": "date",
}
),
2023-05-10 15:06:57 +05:30
}
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["recruitment_id"].widget.attrs = {"data-widget": "ajax-widget"}
self.fields["job_position_id"].widget.attrs = {"data-widget": "ajax-widget"}
2023-05-10 15:06:57 +05:30
class RecruitmentDropDownForm(DropDownForm):
"""
Form for Recruitment model
"""
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
fields = "__all__"
2023-05-10 15:06:57 +05:30
model = Recruitment
widgets = {
"start_date": forms.DateInput(attrs={"type": "date"}),
"end_date": forms.DateInput(attrs={"type": "date"}),
"description": forms.Textarea(attrs={"data-summernote": ""}),
2023-05-10 15:06:57 +05:30
}
labels = {"description": _("Description"), "vacancy": _("Vacancy")}
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["job_position_id"].widget.attrs.update({"id": uuid.uuid4})
self.fields["recruitment_managers"].widget.attrs.update({"id": uuid.uuid4})
field = self.fields["is_active"]
2023-05-10 15:06:57 +05:30
field.widget = field.hidden_widget()
class AddCandidateForm(ModelForm):
"""
Form for Candidate model
"""
verbose_name = "Add Candidate"
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = Candidate
fields = [
"profile",
"resume",
"name",
"email",
"mobile",
"gender",
"stage_id",
"job_position_id",
2023-05-10 15:06:57 +05:30
]
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
initial = kwargs["initial"].get("stage_id")
if initial:
recruitment = Stage.objects.get(id=initial).recruitment_id
self.instance.recruitment_id = recruitment
self.fields["stage_id"].queryset = self.fields["stage_id"].queryset.filter(
recruitment_id=recruitment
)
self.fields["job_position_id"].queryset = recruitment.open_positions
self.fields["gender"].empty_label = None
self.fields["job_position_id"].empty_label = None
self.fields["stage_id"].empty_label = None
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
2023-05-10 15:06:57 +05:30
class StageDropDownForm(DropDownForm):
"""
Form for Stage model
"""
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = Stage
fields = "__all__"
exclude = ["sequence", "is_active"]
2023-05-10 15:06:57 +05:30
labels = {
"stage": _("Stage"),
2023-05-10 15:06:57 +05:30
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
2023-05-10 15:06:57 +05:30
stage = Stage.objects.last()
if stage is not None and stage.sequence is not None:
self.instance.sequence = stage.sequence + 1
else:
self.instance.sequence = 1
class MultipleFileInput(forms.ClearableFileInput):
allow_multiple_selected = True
class MultipleFileField(forms.FileField):
def __init__(self, *args, **kwargs):
kwargs.setdefault("widget", MultipleFileInput())
super().__init__(*args, **kwargs)
def clean(self, data, initial=None):
single_file_clean = super().clean
if isinstance(data, (list, tuple)):
result = [single_file_clean(d, initial) for d in data]
else:
result = [
single_file_clean(data, initial),
]
return result[0] if result else []
2023-05-10 15:06:57 +05:30
class StageNoteForm(ModelForm):
"""
Form for StageNote model
"""
2023-05-10 15:06:57 +05:30
class Meta:
"""
Meta class to add the additional info
"""
2023-05-10 15:06:57 +05:30
model = StageNote
# exclude = (
# "updated_by",
# "stage_id",
# )
fields = ["description"]
exclude = ["is_active"]
2023-05-10 15:06:57 +05:30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# field = self.fields["candidate_id"]
# field.widget = field.hidden_widget()
self.fields["stage_files"] = MultipleFileField(label="files")
self.fields["stage_files"].required = False
def save(self, commit: bool = ...) -> Any:
attachment = []
multiple_attachment_ids = []
attachments = None
if self.files.getlist("stage_files"):
attachments = self.files.getlist("stage_files")
self.instance.attachement = attachments[0]
multiple_attachment_ids = []
for attachment in attachments:
file_instance = StageFiles()
file_instance.files = attachment
file_instance.save()
multiple_attachment_ids.append(file_instance.pk)
instance = super().save(commit)
if commit:
instance.stage_files.add(*multiple_attachment_ids)
return instance, multiple_attachment_ids
class StageNoteUpdateForm(ModelForm):
class Meta:
"""
Meta class to add the additional info
"""
model = StageNote
exclude = ["updated_by", "stage_id", "stage_files", "is_active"]
fields = "__all__"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
field = self.fields["candidate_id"]
field.widget = field.hidden_widget()
class QuestionForm(ModelForm):
"""
QuestionForm
"""
verbose_name = "Survey Questions"
recruitment = forms.ModelMultipleChoiceField(
queryset=Recruitment.objects.filter(is_active=True),
required=False,
2023-08-22 13:57:44 +05:30
label=_("Recruitment"),
)
# job_positions = forms.ModelMultipleChoiceField(
# queryset=JobPosition.objects.all(), required=False, label=_("Job Positions")
# )
class Meta:
"""
Class Meta for additional options
"""
model = RecruitmentSurvey
fields = "__all__"
exclude = [
"recruitment_ids",
"job_position_ids",
"is_active",
]
2023-08-22 13:57:44 +05:30
labels = {
"question": _("Question"),
"sequence": _("Sequence"),
"type": _("Type"),
"options": _("Options"),
"is_mandatory": _("Is Mandatory"),
2023-08-22 13:57:44 +05:30
}
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string(
"survey/question_template_organized_form.html", context
)
return table_html
def clean(self):
super().clean()
recruitment = self.cleaned_data["recruitment"]
# jobs = self.cleaned_data["job_positions"]
qtype = self.cleaned_data["type"]
options = self.cleaned_data["options"]
if not recruitment.exists(): # or jobs.exists()):
raise ValidationError(
{"recruitment": _("Choose any recruitment to apply this question")}
)
self.recruitment = recruitment
# self.job_positions = jobs
if qtype in ["options", "multiple"] and (options is None or options == ""):
raise ValidationError({"options": "Options field is required"})
return
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = kwargs.get("instance", None)
if instance:
self.fields["recruitment"].initial = instance.recruitment_ids.all()
# self.fields["job_positions"].initial = instance.job_position_ids.all()
self.fields["type"].widget.attrs.update(
{"class": " w-100", "style": "border:solid 1px #6c757d52;height:50px;"}
)
self.fields["options"].required = False
class SurveyForm(forms.Form):
"""
SurveyTemplateForm
"""
def __init__(self, recruitment, *args, **kwargs) -> None:
super().__init__(recruitment, *args, **kwargs)
questions = recruitment.recruitmentsurvey_set.all()
context = {"form": self, "questions": questions}
form = render_to_string("survey_form.html", context)
self.form = form
return
# for question in questions:
# self
class TemplateForm(ModelForm):
"""
TemplateForm
"""
verbose_name = "Template"
class Meta:
model = SurveyTemplate
fields = "__all__"
exclude = ["is_active"]
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
class AddQuestionForm(Form):
"""
AddQuestionForm
"""
verbose_name = "Add Question"
question_ids = forms.ModelMultipleChoiceField(
queryset=RecruitmentSurvey.objects.all(), label="Questions"
)
template_ids = forms.ModelMultipleChoiceField(
queryset=SurveyTemplate.objects.all(), label="Templates"
)
def save(self):
"""
Manual save/adding of questions to the templates
"""
for question in self.cleaned_data["question_ids"]:
question.template_id.add(*self.data["template_ids"])
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
exclude_fields = ["id", "profile", "portfolio", "resume", "sequence", "schedule_date"]
class CandidateExportForm(forms.Form):
model_fields = Candidate._meta.get_fields()
field_choices = [
(field.name, field.verbose_name.capitalize())
for field in model_fields
if hasattr(field, "verbose_name") and field.name not in exclude_fields
]
field_choices = field_choices + [
("rejected_candidate__description", "Rejected Description"),
]
selected_fields = forms.MultipleChoiceField(
choices=field_choices,
widget=forms.CheckboxSelectMultiple,
initial=[
"name",
"recruitment_id",
"job_position_id",
"stage_id",
"email",
"mobile",
"hired",
"joining_date",
],
)
2023-12-21 17:15:25 +05:30
class OfferLetterForm(ModelForm):
"""
OfferLetterForm
"""
class Meta:
model = RecruitmentMailTemplate
fields = "__all__"
# exclude = ["is_active"]
2023-12-21 17:15:25 +05:30
widgets = {
"body": forms.Textarea(
attrs={"data-summernote": "", "style": "display:none;"}
),
}
def get_template_language(self):
mail_data = {
"Receiver|Full name": "instance.get_full_name",
"Sender|Full name": "self.get_full_name",
"Receiver|Recruitment": "instance.recruitment_id",
"Sender|Recruitment": "self.recruitment_id",
"Receiver|Company": "instance.get_company",
"Sender|Company": "self.get_company",
"Receiver|Job position": "instance.get_job_position",
"Sender|Job position": "self.get_job_position",
"Receiver|Email": "instance.get_mail",
"Sender|Email": "self.get_mail",
"Receiver|Employee Type": "instance.get_employee_type",
"Sender|Employee Type": "self.get_employee_type",
"Receiver|Work Type": "instance.get_work_type",
"Sender|Work Type": "self.get_work_type",
"Candidate|Full name": "instance.get_full_name",
"Candidate|Recruitment": "instance.recruitment_id",
"Candidate|Company": "instance.get_company",
"Candidate|Job position": "instance.get_job_position",
"Candidate|Email": "instance.get_email",
"Candidate|Interview Table": "instance.get_interview|safe",
}
return mail_data
class SkillZoneCreateForm(ModelForm):
verbose_name = "Skill Zone"
class Meta:
"""
Class Meta for additional options
"""
model = SkillZone
fields = "__all__"
exclude = ["is_active"]
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
class SkillZoneCandidateForm(ModelForm):
verbose_name = "Skill Zone Candidate"
candidate_id = forms.ModelMultipleChoiceField(
queryset=Candidate.objects.all(),
widget=forms.SelectMultiple,
label=_("Candidate"),
)
class Meta:
"""
Class Meta for additional options
"""
model = SkillZoneCandidate
fields = "__all__"
exclude = [
"added_on",
"is_active",
]
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
def clean_candidate_id(self):
selected_candidates = self.cleaned_data["candidate_id"]
# Ensure all selected candidates are instances of the Candidate model
for candidate in selected_candidates:
if not isinstance(candidate, Candidate):
raise forms.ValidationError("Invalid candidate selected.")
return selected_candidates.first()
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.fields["candidate_id"].empty_label = None
if self.instance.pk:
self.verbose_name = (
self.instance.candidate_id.name
+ " / "
+ self.instance.skill_zone_id.title
)
def save(self, commit: bool = ...) -> Any:
super().save(commit)
other_candidates = list(
set(self.data.getlist("candidate_id"))
- {
str(self.instance.candidate_id.id),
}
)
if commit:
cand = self.instance
for id in other_candidates:
cand.pk = None
cand.id = None
cand.candidate_id = Candidate.objects.get(id=id)
try:
super(SkillZoneCandidate, cand).save()
except Exception as e:
logger.error(e)
return other_candidates
class ToSkillZoneForm(ModelForm):
verbose_name = "Add To Skill Zone"
skill_zone_ids = forms.ModelMultipleChoiceField(
queryset=SkillZone.objects.all(), label=_("Skill Zones")
)
class Meta:
"""
Class Meta for additional options
"""
model = SkillZoneCandidate
fields = "__all__"
exclude = [
"skill_zone_id",
"is_active",
"candidate_id",
]
error_messages = {
NON_FIELD_ERRORS: {
"unique_together": "This candidate alreay exist in this skill zone",
}
}
def clean(self):
cleaned_data = super().clean()
candidate = cleaned_data.get("candidate_id")
skill_zones = cleaned_data.get("skill_zone_ids")
skill_zone_list = []
for skill_zone in skill_zones:
# Check for the unique together constraint manually
if SkillZoneCandidate.objects.filter(
candidate_id=candidate, skill_zone_id=skill_zone
).exists():
# Raise a ValidationError with a custom error message
skill_zone_list.append(skill_zone)
if len(skill_zone_list) > 0:
skill_zones_str = ", ".join(
str(skill_zone) for skill_zone in skill_zone_list
)
raise ValidationError(f"{candidate} already exists in {skill_zones_str}.")
# cleaned_data['skill_zone_id'] =skill_zone
return cleaned_data
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
class RejectReasonForm(ModelForm):
"""
RejectReasonForm
"""
verbose_name = "Reject Reason"
class Meta:
model = RejectReason
fields = "__all__"
exclude = ["is_active"]
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
class RejectedCandidateForm(ModelForm):
"""
RejectedCandidateForm
"""
verbose_name = "Rejected Candidate"
class Meta:
model = RejectedCandidate
fields = "__all__"
exclude = ["is_active"]
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["reject_reason_id"].empty_label = None
self.fields["candidate_id"].widget = self.fields["candidate_id"].hidden_widget()
class ScheduleInterviewForm(ModelForm):
"""
ScheduleInterviewForm
"""
verbose_name = "Schedule Interview"
class Meta:
model = InterviewSchedule
fields = "__all__"
exclude = ["is_active"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["interview_date"].widget = forms.DateInput(
attrs={"type": "date", "class": "oh-input w-100"}
)
self.fields["interview_time"].widget = forms.TimeInput(
attrs={"type": "time", "class": "oh-input w-100"}
)
def clean(self):
instance = self.instance
cleaned_data = super().clean()
interview_date = cleaned_data.get("interview_date")
interview_time = cleaned_data.get("interview_time")
managers = cleaned_data["employee_id"]
if not instance.pk and interview_date and interview_date < date.today():
self.add_error("interview_date", _("Interview date cannot be in the past."))
if not instance.pk and interview_time:
now = datetime.now().time()
if (
not instance.pk
and interview_date == date.today()
and interview_time < now
):
self.add_error(
"interview_time", _("Interview time cannot be in the past.")
)
leave_employees = LeaveRequest.objects.filter(
employee_id__in=managers, status="approved"
)
employees = [
leave.employee_id.get_full_name()
for leave in leave_employees
if interview_date in leave.requested_dates()
]
if employees:
self.add_error(
"employee_id", _(f"{employees} have approved leave on this date")
)
return cleaned_data
def as_p(self, *args, **kwargs):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("common_form.html", context)
return table_html