650 lines
20 KiB
Python
650 lines
20 KiB
Python
"""
|
|
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:
|
|
from django import forms
|
|
|
|
class YourForm(forms.Form):
|
|
field_name = forms.CharField()
|
|
|
|
def clean_field_name(self):
|
|
# Custom validation logic goes here
|
|
pass
|
|
"""
|
|
|
|
from ast import Dict
|
|
from typing import Any
|
|
import uuid
|
|
from django import forms
|
|
from django.core.exceptions import ValidationError
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.template.loader import render_to_string
|
|
from employee.filters import EmployeeFilter
|
|
from employee.models import Employee
|
|
from horilla_widgets.widgets.horilla_multi_select_field import HorillaMultiSelectField
|
|
from horilla_widgets.widgets.select_widgets import HorillaMultiSelectWidget
|
|
from recruitment.models import (
|
|
Stage,
|
|
Recruitment,
|
|
Candidate,
|
|
StageNote,
|
|
JobPosition,
|
|
RecruitmentSurvey,
|
|
RecruitmentMailTemplate,
|
|
)
|
|
from recruitment import widgets
|
|
from base.methods import reload_queryset
|
|
|
|
|
|
class ModelForm(forms.ModelForm):
|
|
"""
|
|
Overriding django default model form to apply some styles
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
reload_queryset(self.fields)
|
|
for field_name, field in self.fields.items():
|
|
widget = field.widget
|
|
if isinstance(
|
|
widget,
|
|
(forms.NumberInput, forms.EmailInput, forms.TextInput, forms.FileInput),
|
|
):
|
|
label = _(field.label)
|
|
field.widget.attrs.update(
|
|
{"class": "oh-input w-100", "placeholder": label}
|
|
)
|
|
elif isinstance(widget, forms.URLInput):
|
|
field.widget.attrs.update(
|
|
{"class": "oh-input w-100", "placeholder": field.label}
|
|
)
|
|
elif isinstance(widget, (forms.Select,)):
|
|
field.empty_label = _("---Choose {label}---").format(
|
|
label=_(field.label)
|
|
)
|
|
self.fields[field_name].widget.attrs.update(
|
|
{
|
|
"id": uuid.uuid4,
|
|
"class": "oh-select oh-select-2 w-100",
|
|
"style": "height:50px;",
|
|
}
|
|
)
|
|
elif isinstance(widget, (forms.Textarea)):
|
|
label = _(field.label)
|
|
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 "})
|
|
|
|
|
|
class RegistrationForm(forms.ModelForm):
|
|
"""
|
|
Overriding django default model form to apply some styles
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
reload_queryset(self.fields)
|
|
for field_name, field in self.fields.items():
|
|
widget = field.widget
|
|
if isinstance(widget, (forms.Select,)):
|
|
label = ""
|
|
if field.label is not None:
|
|
label = _(field.label)
|
|
field.empty_label = _("---Choose {label}---").format(label=label)
|
|
self.fields[field_name].widget.attrs.update(
|
|
{"id": uuid.uuid4, "class": "oh-select-2 oh-select--sm w-100"}
|
|
)
|
|
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 "})
|
|
|
|
|
|
class DropDownForm(forms.ModelForm):
|
|
"""
|
|
Overriding django default model form to apply some styles
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
reload_queryset(self.fields)
|
|
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,
|
|
}
|
|
)
|
|
elif isinstance(widget, (forms.Select,)):
|
|
self.fields[field_name].widget.attrs.update(
|
|
{
|
|
"class": "oh-select-2 oh-select--xs-forced ",
|
|
"id": uuid.uuid4(),
|
|
}
|
|
)
|
|
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 "})
|
|
|
|
|
|
class RecruitmentCreationForm(ModelForm):
|
|
"""
|
|
Form for Recruitment model
|
|
"""
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = Recruitment
|
|
fields = "__all__"
|
|
widgets = {
|
|
"start_date": forms.DateInput(attrs={"type": "date"}),
|
|
"end_date": forms.DateInput(attrs={"type": "date"}),
|
|
"description": forms.Textarea(attrs={"data-summernote": ""}),
|
|
}
|
|
labels = {"description": _("Description"), "vacancy": _("Vacancy")}
|
|
|
|
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()
|
|
|
|
|
|
class StageCreationForm(ModelForm):
|
|
"""
|
|
Form for Stage model
|
|
"""
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = Stage
|
|
fields = "__all__"
|
|
exclude = ("sequence",)
|
|
labels = {
|
|
"stage": _("Stage"),
|
|
}
|
|
|
|
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()
|
|
|
|
|
|
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"}
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = Candidate
|
|
fields = "__all__"
|
|
exclude = (
|
|
"confirmation",
|
|
"scheduled_for",
|
|
"schedule_date",
|
|
"joining_date",
|
|
"sequence",
|
|
"stage_id",
|
|
"offerletter_status",
|
|
)
|
|
widgets = {
|
|
"scheduled_date": forms.DateInput(attrs={"type": "date"}),
|
|
"dob": forms.DateInput(attrs={"type": "date"}),
|
|
}
|
|
labels = {
|
|
"name": _("Name"),
|
|
"email": _("Email"),
|
|
"mobile": _("Mobile"),
|
|
"address": _("Address"),
|
|
"zip": _("Zip"),
|
|
}
|
|
|
|
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:
|
|
candidate.hired = True
|
|
candidate.start_onboard = True
|
|
candidate.recruitment_id = recruitment
|
|
candidate.stage_id = stage
|
|
job_id = self.data["job_position_id"]
|
|
job_position = JobPosition.objects.get(id=job_id)
|
|
self.instance.job_position_id = job_position
|
|
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["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()
|
|
|
|
|
|
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)
|
|
recruitment_id = forms.ModelChoiceField(queryset=active_recruitment)
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = Candidate
|
|
exclude = (
|
|
"stage_id",
|
|
"schedule_date",
|
|
"referral",
|
|
"start_onboard",
|
|
"hired",
|
|
"is_active",
|
|
"canceled",
|
|
"joining_date",
|
|
"sequence",
|
|
"offerletter_status",
|
|
"source",
|
|
)
|
|
widgets = {
|
|
"recruitment_id": forms.TextInput(
|
|
attrs={
|
|
"required": "required",
|
|
}
|
|
),
|
|
"dob": forms.DateInput(
|
|
attrs={
|
|
"type": "date",
|
|
}
|
|
),
|
|
}
|
|
|
|
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"}
|
|
|
|
|
|
class RecruitmentDropDownForm(DropDownForm):
|
|
"""
|
|
Form for Recruitment model
|
|
"""
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
fields = "__all__"
|
|
model = Recruitment
|
|
widgets = {
|
|
"start_date": forms.DateInput(attrs={"type": "date"}),
|
|
"end_date": forms.DateInput(attrs={"type": "date"}),
|
|
"description": forms.Textarea(attrs={"data-summernote": ""}),
|
|
}
|
|
labels = {"description": _("Description"), "vacancy": _("Vacancy")}
|
|
|
|
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"]
|
|
field.widget = field.hidden_widget()
|
|
|
|
|
|
class CandidateDropDownForm(DropDownForm):
|
|
"""
|
|
Form for Candidate model
|
|
"""
|
|
|
|
profile = forms.FileField(required=False)
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = Candidate
|
|
fields = [
|
|
"name",
|
|
"email",
|
|
"mobile",
|
|
"resume",
|
|
"stage_id",
|
|
"recruitment_id",
|
|
"job_position_id",
|
|
"profile",
|
|
]
|
|
labels = {
|
|
"name": _("Name"),
|
|
"email": _("Email"),
|
|
"mobile": _("Mobile"),
|
|
"job_position_id": _("Job Position"),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.fields["recruitment_id"].widget.attrs.update({"id": uuid.uuid4})
|
|
self.fields["stage_id"].widget.attrs.update({"id": uuid.uuid4})
|
|
|
|
|
|
class StageDropDownForm(DropDownForm):
|
|
"""
|
|
Form for Stage model
|
|
"""
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = Stage
|
|
fields = "__all__"
|
|
exclude = [
|
|
"sequence",
|
|
]
|
|
labels = {
|
|
"stage": _("Stage"),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
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 StageNoteForm(ModelForm):
|
|
"""
|
|
Form for StageNote model
|
|
"""
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class to add the additional info
|
|
"""
|
|
|
|
model = StageNote
|
|
exclude = (
|
|
"updated_by",
|
|
"stage_id",
|
|
)
|
|
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
|
|
"""
|
|
|
|
recruitment = forms.ModelMultipleChoiceField(
|
|
queryset=Recruitment.objects.filter(is_active=True),
|
|
required=False,
|
|
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",
|
|
]
|
|
labels = {
|
|
"question": _("Question"),
|
|
"sequence": _("Sequence"),
|
|
"type": _("Type"),
|
|
"options": _("Options"),
|
|
"is_mandatory": _("Is Mandatory"),
|
|
}
|
|
|
|
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(
|
|
"Choose any recruitment or job positions 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)
|
|
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
|
|
|
|
|
|
exclude_fields = ["id", "profile", "portfolio", "resume", "sequence"]
|
|
|
|
|
|
class CandidateExportForm(forms.Form):
|
|
model_fields = Candidate._meta.get_fields()
|
|
field_choices = [
|
|
(field.name, field.verbose_name)
|
|
for field in model_fields
|
|
if hasattr(field, "verbose_name") and field.name not in exclude_fields
|
|
]
|
|
selected_fields = forms.MultipleChoiceField(
|
|
choices=field_choices,
|
|
widget=forms.CheckboxSelectMultiple,
|
|
initial=[
|
|
"name",
|
|
"recruitment_id",
|
|
"job_position_id",
|
|
"stage_id",
|
|
"schedule_date",
|
|
"email",
|
|
"mobile",
|
|
"hired",
|
|
"joining_date",
|
|
],
|
|
)
|
|
|
|
|
|
class OfferLetterForm(ModelForm):
|
|
"""
|
|
OfferLetterForm
|
|
"""
|
|
|
|
class Meta:
|
|
model = RecruitmentMailTemplate
|
|
fields = "__all__"
|
|
widgets = {
|
|
"body": forms.Textarea(
|
|
attrs={"data-summernote": "", "style": "display:none;"}
|
|
),
|
|
}
|