349 lines
11 KiB
Python
349 lines
11 KiB
Python
"""
|
|
These forms provide a convenient way to handle data input, validation, and customization
|
|
of form fields and widgets for the corresponding models in the payroll management system.
|
|
"""
|
|
import uuid
|
|
import datetime
|
|
from django import forms
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.template.loader import render_to_string
|
|
from horilla_widgets.forms import HorillaForm
|
|
from horilla_widgets.widgets.horilla_multi_select_field import HorillaMultiSelectField
|
|
from horilla_widgets.widgets.select_widgets import HorillaMultiSelectWidget
|
|
from base.forms import Form, ModelForm
|
|
from employee.models import Employee
|
|
from employee.filters import EmployeeFilter
|
|
from payroll.models import tax_models as models
|
|
from payroll.widgets import component_widgets as widget
|
|
from payroll.models.models import Allowance, Contract
|
|
import payroll.models.models
|
|
from base.methods import reload_queryset
|
|
|
|
|
|
class AllowanceForm(forms.ModelForm):
|
|
"""
|
|
Form for Allowance model
|
|
"""
|
|
|
|
load = forms.CharField(widget=widget.AllowanceConditionalVisibility, required=False)
|
|
style = forms.CharField(required=False)
|
|
verbose_name = _("Allowance")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class for additional options
|
|
"""
|
|
|
|
model = payroll.models.models.Allowance
|
|
fields = "__all__"
|
|
widgets = {
|
|
"one_time_date": forms.DateTimeInput(attrs={"type": "date"}),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
if instance := kwargs.get("instance"):
|
|
# django forms not showing value inside the date, time html element.
|
|
# so here overriding default forms instance method to set initial value
|
|
initial = {}
|
|
if instance.one_time_date is not None:
|
|
initial = {
|
|
"one_time_date": instance.one_time_date.strftime("%Y-%m-%d"),
|
|
}
|
|
kwargs["initial"] = initial
|
|
super().__init__(*args, **kwargs)
|
|
reload_queryset(self.fields)
|
|
self.fields["style"].widget = widget.StyleWidget(form=self)
|
|
|
|
def as_p(self):
|
|
"""
|
|
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 DeductionForm(forms.ModelForm):
|
|
"""
|
|
Form for Deduction model
|
|
"""
|
|
|
|
load = forms.CharField(widget=widget.DeductionConditionalVisibility, required=False)
|
|
style = forms.CharField(required=False)
|
|
verbose_name = _("Deduction")
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class for additional options
|
|
"""
|
|
|
|
model = payroll.models.models.Deduction
|
|
fields = "__all__"
|
|
widgets = {
|
|
"one_time_date": forms.DateTimeInput(attrs={"type": "date"}),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
if instance := kwargs.get("instance"):
|
|
# django forms not showing value inside the date, time html element.
|
|
# so here overriding default forms instance method to set initial value
|
|
initial = {}
|
|
if instance.one_time_date is not None:
|
|
initial = {
|
|
"one_time_date": instance.one_time_date.strftime("%Y-%m-%d"),
|
|
}
|
|
kwargs["initial"] = initial
|
|
super().__init__(*args, **kwargs)
|
|
reload_queryset(self.fields)
|
|
self.fields["style"].widget = widget.StyleWidget(form=self)
|
|
|
|
def clean(self):
|
|
if (
|
|
self.data.get("update_compensation") is not None
|
|
and self.data.get("update_compensation") != ""
|
|
):
|
|
if (
|
|
self.data.getlist("specific_employees") is None
|
|
and len(self.data.getlist("specific_employees")) == 0
|
|
):
|
|
raise forms.ValidationError(
|
|
{"specific_employees": "You need to choose the employee."}
|
|
)
|
|
|
|
if (
|
|
self.data.get("one_time_date") is None
|
|
and self.data.get("one_time_date") == ""
|
|
):
|
|
raise forms.ValidationError(
|
|
{"one_time_date": "This field is required."}
|
|
)
|
|
if self.data.get("amount") is None and self.data.get("amount") == "":
|
|
raise forms.ValidationError({"amount": "This field is required."})
|
|
return super().clean()
|
|
|
|
def as_p(self):
|
|
"""
|
|
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 PayslipForm(ModelForm):
|
|
"""
|
|
Form for Payslip
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
active_contracts = Contract.objects.filter(contract_status="active")
|
|
self.fields["employee_id"].choices = [
|
|
(contract.employee_id.id, contract.employee_id)
|
|
for contract in active_contracts
|
|
if contract.employee_id.is_active
|
|
]
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class for additional options
|
|
"""
|
|
|
|
model = payroll.models.models.Payslip
|
|
fields = [
|
|
"employee_id",
|
|
"start_date",
|
|
"end_date",
|
|
]
|
|
widgets = {
|
|
"start_date": forms.DateInput(attrs={"type": "date"}),
|
|
"end_date": forms.DateInput(attrs={"type": "date"}),
|
|
}
|
|
|
|
|
|
class GeneratePayslipForm(HorillaForm):
|
|
"""
|
|
Form for Payslip
|
|
"""
|
|
|
|
group_name = forms.CharField(
|
|
label="Batch name",
|
|
required=False,
|
|
# help_text="Enter +-something if you want to generate payslips by batches",
|
|
)
|
|
employee_id = HorillaMultiSelectField(
|
|
queryset=Employee.objects.none(),
|
|
widget=HorillaMultiSelectWidget(
|
|
filter_route_name="employee-widget-filter",
|
|
filter_class=EmployeeFilter,
|
|
filter_instance_contex_name="f",
|
|
filter_template_path="employee_filters.html",
|
|
),
|
|
label="Employee",
|
|
)
|
|
start_date = forms.DateField(widget=forms.DateInput(attrs={"type": "date"}))
|
|
end_date = forms.DateField(widget=forms.DateInput(attrs={"type": "date"}))
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
start_date = cleaned_data.get("start_date")
|
|
end_date = cleaned_data.get("end_date")
|
|
|
|
today = datetime.date.today()
|
|
if end_date < start_date:
|
|
raise forms.ValidationError(
|
|
{
|
|
"end_date": "The end date must be greater than or equal to the start date."
|
|
}
|
|
)
|
|
if start_date > today:
|
|
raise forms.ValidationError(
|
|
{"end_date": "The start date cannot be in the future."}
|
|
)
|
|
|
|
if end_date > today:
|
|
raise forms.ValidationError(
|
|
{"end_date": "The end date cannot be in the future."}
|
|
)
|
|
return cleaned_data
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.fields["employee_id"].queryset = Employee.objects.filter(
|
|
is_active=True,
|
|
contract_set__isnull=False,
|
|
contract_set__contract_status="active",
|
|
)
|
|
self.fields["employee_id"].widget.attrs.update(
|
|
{"class": "oh-select oh-select-2", "id": uuid.uuid4()}
|
|
)
|
|
self.fields["start_date"].widget.attrs.update({"class": "oh-input w-100"})
|
|
self.fields["group_name"].widget.attrs.update({"class": "oh-input w-100"})
|
|
self.fields["end_date"].widget.attrs.update({"class": "oh-input w-100"})
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class for additional options
|
|
"""
|
|
|
|
widgets = {
|
|
"start_date": forms.DateInput(attrs={"type": "date"}),
|
|
"end_date": forms.DateInput(attrs={"type": "date"}),
|
|
}
|
|
|
|
|
|
class PayrollSettingsForm(ModelForm):
|
|
"""
|
|
Form for PayrollSettings model
|
|
"""
|
|
|
|
class Meta:
|
|
"""
|
|
Meta class for additional options
|
|
"""
|
|
|
|
model = models.PayrollSettings
|
|
fields = "__all__"
|
|
|
|
|
|
excel_columns = [
|
|
("employee_id", _("Employee")),
|
|
("group_name", _("Batch")),
|
|
("start_date", _("Start Date")),
|
|
("end_date", _("End Date")),
|
|
("contract_wage", _("Contract Wage")),
|
|
("basic_pay", _("Basic Pay")),
|
|
("gross_pay", _("Gross Pay")),
|
|
("deduction", _("Deduction")),
|
|
("net_pay", _("Net Pay")),
|
|
("status", _("Status")),
|
|
("employee_id__employee_bank_details__bank_name", _("Bank Name")),
|
|
("employee_id__employee_bank_details__branch", _("Branch")),
|
|
("employee_id__employee_bank_details__account_number", _("Account Number")),
|
|
("employee_id__employee_bank_details__any_other_code1", _("Bank Code #1")),
|
|
("employee_id__employee_bank_details__any_other_code2", _("Bank Code #2")),
|
|
("employee_id__employee_bank_details__country", _("Country")),
|
|
("employee_id__employee_bank_details__state", _("State")),
|
|
("employee_id__employee_bank_details__city", _("City")),
|
|
]
|
|
|
|
|
|
class PayslipExportColumnForm(forms.Form):
|
|
selected_fields = forms.MultipleChoiceField(
|
|
choices=excel_columns,
|
|
widget=forms.CheckboxSelectMultiple,
|
|
initial=[
|
|
"employee_id",
|
|
"group_name",
|
|
"start_date",
|
|
"end_date",
|
|
"basic_pay",
|
|
"gross_pay",
|
|
"net_pay",
|
|
"status",
|
|
],
|
|
)
|
|
|
|
|
|
exclude_fields = ["id", "contract_document", "is_active", "note", "note"]
|
|
|
|
|
|
class ContractExportFieldForm(forms.Form):
|
|
model_fields = Contract._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=[
|
|
"contract_name",
|
|
"employee_id",
|
|
"contract_start_date",
|
|
"contract_end_date",
|
|
"wage_type",
|
|
"wage",
|
|
"filing_status",
|
|
"contract_status",
|
|
],
|
|
)
|
|
|
|
|
|
class BonusForm(Form):
|
|
"""
|
|
Bonus Creating Form
|
|
"""
|
|
title = forms.CharField(max_length=100)
|
|
date = forms.DateField(widget=forms.DateInput())
|
|
employee_id = forms.IntegerField(label="Employee",widget=forms.HiddenInput())
|
|
amount = forms.DecimalField(label="Amount")
|
|
|
|
def save(self, commit=True):
|
|
title = self.cleaned_data["title"]
|
|
date = self.cleaned_data["date"]
|
|
employee_id = self.cleaned_data["employee_id"]
|
|
amount = self.cleaned_data["amount"]
|
|
|
|
bonus = Allowance()
|
|
bonus.title = title
|
|
bonus.one_time_date = date
|
|
bonus.only_show_under_employee = True
|
|
bonus.amount = amount
|
|
bonus.is_fixed = True
|
|
bonus.save()
|
|
bonus.include_active_employees = False
|
|
bonus.specific_employees.set([employee_id])
|
|
bonus.save()
|
|
|
|
return bonus
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
for field_name, field in self.fields.items():
|
|
field.widget.attrs.update({"class": "oh-input w-100"})
|
|
self.fields["date"].widget = forms.DateInput(
|
|
attrs={"type": "date", "class": "oh-input w-100"}
|
|
)
|