280 lines
11 KiB
Python
280 lines
11 KiB
Python
from rest_framework import serializers
|
|
from employee.models import BonusPoint, Employee
|
|
from leave.models import LeaveType
|
|
from payroll.models.models import Allowance, Contract, Deduction, LoanAccount, MultipleCondition, Payslip, Reimbursement, ReimbursementMultipleAttachment
|
|
from payroll.models.tax_models import TaxBracket
|
|
|
|
|
|
class PayslipSerializer(serializers.ModelSerializer):
|
|
employee_first_name = serializers.CharField(
|
|
source="employee_id.employee_first_name", read_only=True)
|
|
employee_last_name = serializers.CharField(
|
|
source="employee_id.employee_last_name", read_only=True)
|
|
shift_name = serializers.CharField(
|
|
source="shift_id.employee_shift", read_only=True)
|
|
badge_id = serializers.CharField(
|
|
source="employee_id.badge_id", read_only=True)
|
|
employee_profile_url = serializers.SerializerMethodField(read_only=True)
|
|
department_name = serializers.CharField(
|
|
source='employee_id.employee_work_info.department_id.department', read_only=True)
|
|
bank_account_check_number = serializers.CharField(
|
|
source='employee_id.employee_bank_details.account_number', read_only=True)
|
|
|
|
|
|
class Meta:
|
|
model = Payslip
|
|
fields = '__all__'
|
|
# exclude = ['reference',
|
|
# 'sent_to_employee',
|
|
# 'installment_ids', 'created_at']
|
|
|
|
|
|
def get_employee_profile_url(self, obj):
|
|
try:
|
|
employee_profile = obj.employee_id.employee_profile
|
|
return employee_profile.url
|
|
except:
|
|
return None
|
|
|
|
class ContractSerializer(serializers.ModelSerializer):
|
|
employee_first_name = serializers.CharField(
|
|
source="employee_id.employee_first_name", read_only=True)
|
|
employee_last_name = serializers.CharField(
|
|
source="employee_id.employee_last_name", read_only=True)
|
|
shift_name = serializers.CharField(
|
|
source="shift_id.employee_shift", read_only=True)
|
|
badge_id = serializers.CharField(
|
|
source="employee_id.badge_id", read_only=True)
|
|
employee_profile_url = serializers.SerializerMethodField(read_only=True)
|
|
|
|
job_position_name = serializers.CharField(
|
|
source='job_position_id.job_position', read_only=True)
|
|
job_role_name = serializers.CharField(
|
|
source='job_role_id.job_role', read_only=True)
|
|
department_name = serializers.CharField(
|
|
source='department_id.department', read_only=True)
|
|
shift_name = serializers.CharField(
|
|
source='shift_id.employee_shift', read_only=True)
|
|
work_type_name = serializers.CharField(
|
|
source='work_type_id.work_type', read_only=True)
|
|
def get_employee_profile_url(self, obj):
|
|
try:
|
|
employee_profile = obj.employee_id.employee_profile
|
|
return employee_profile.url
|
|
except:
|
|
return None
|
|
|
|
class Meta:
|
|
model = Contract
|
|
fields = '__all__'
|
|
|
|
|
|
class MultipleConditionSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = MultipleCondition
|
|
fields = '__all__'
|
|
|
|
|
|
class AllowanceSerializer(serializers.ModelSerializer):
|
|
specific_employees = serializers.PrimaryKeyRelatedField(
|
|
queryset=Employee.objects.all(), many=True, required=False
|
|
)
|
|
exclude_employees = serializers.PrimaryKeyRelatedField(
|
|
queryset=Employee.objects.all(), many=True, required=False
|
|
)
|
|
other_conditions = serializers.PrimaryKeyRelatedField(
|
|
queryset=MultipleCondition.objects.all(), many=True, required=False
|
|
)
|
|
|
|
class Meta:
|
|
model = Allowance
|
|
fields = '__all__'
|
|
read_only_fields = ['id', 'company_id', 'only_show_under_employee', 'is_loan']
|
|
|
|
def create(self, validated_data):
|
|
specific_employees = validated_data.pop('specific_employees', [])
|
|
exclude_employees = validated_data.pop('exclude_employees', [])
|
|
other_conditions = validated_data.pop('other_conditions', [])
|
|
|
|
allowance = Allowance.objects.create(**validated_data)
|
|
|
|
# Set the ManyToMany relationships after the instance is created
|
|
allowance.specific_employees.set(specific_employees)
|
|
allowance.exclude_employees.set(exclude_employees)
|
|
allowance.other_conditions.set(other_conditions)
|
|
|
|
return allowance
|
|
|
|
def validate(self, data):
|
|
is_fixed = data.get('is_fixed')
|
|
amount = data.get('amount')
|
|
based_on = data.get('based_on')
|
|
per_attendance_fixed_amount = data.get('per_attendance_fixed_amount')
|
|
shift_id = data.get('shift_id')
|
|
work_type_id = data.get('work_type_id')
|
|
is_condition_based = data.get('is_condition_based')
|
|
field = data.get('field')
|
|
condition = data.get('condition')
|
|
value = data.get('value')
|
|
has_max_limit = data.get('has_max_limit')
|
|
maximum_amount = data.get('maximum_amount')
|
|
|
|
if is_fixed and (amount is None or amount < 0):
|
|
raise serializers.ValidationError("If 'is_fixed' is True, 'amount' must be a positive number.")
|
|
|
|
if not is_fixed and not based_on:
|
|
raise serializers.ValidationError("If 'is_fixed' is False, 'based_on' is required.")
|
|
|
|
if based_on == "attendance" and not per_attendance_fixed_amount:
|
|
raise serializers.ValidationError("If 'based_on' is 'attendance', 'per_attendance_fixed_amount' is required.")
|
|
|
|
if based_on == "shift_id" and not shift_id:
|
|
raise serializers.ValidationError("If 'based_on' is 'shift_id', 'shift_id' is required.")
|
|
|
|
if based_on == "work_type_id" and not work_type_id:
|
|
raise serializers.ValidationError("If 'based_on' is 'work_type_id', 'work_type_id' is required.")
|
|
|
|
if is_condition_based and (not field or not value or not condition):
|
|
raise serializers.ValidationError("If 'is_condition_based' is True, 'field', 'value', and 'condition' are required.")
|
|
|
|
if has_max_limit and maximum_amount is None:
|
|
raise serializers.ValidationError("If 'has_max_limit' is True, 'maximum_amount' is required.")
|
|
|
|
return data
|
|
class DeductionSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = Deduction
|
|
fields = '__all__'
|
|
|
|
|
|
class LoanAccountSerializer(serializers.ModelSerializer):
|
|
employee_profile_url = serializers.SerializerMethodField(read_only=True)
|
|
employee_full_name = serializers.CharField(source='employee_id.get_full_name',read_only=True)
|
|
badge_id = serializers.CharField(source='employee_id.badge_id',read_only=True)
|
|
job_position_name = serializers.CharField(source='employee_id.get_job_position',read_only=True)
|
|
class Meta:
|
|
model = LoanAccount
|
|
fields = '__all__'
|
|
|
|
def get_employee_profile_url(self, obj):
|
|
try:
|
|
employee_profile = obj.employee_id.employee_profile
|
|
return employee_profile.url
|
|
except:
|
|
return None
|
|
|
|
|
|
class ReimbursementSerializer(serializers.ModelSerializer):
|
|
other_attachements = serializers.SerializerMethodField()
|
|
leave_type_name = serializers.CharField(source='leave_type_id.name',read_only=True)
|
|
employee_profile_url = serializers.SerializerMethodField(read_only=True)
|
|
badge_id = serializers.CharField(source='employee_id.badge_id')
|
|
employee_full_name = serializers.CharField(source='employee_id.get_full_name')
|
|
|
|
def get_employee_profile_url(self, obj):
|
|
try:
|
|
employee_profile = obj.employee_id.employee_profile
|
|
return employee_profile.url
|
|
except:
|
|
return None
|
|
|
|
class Meta:
|
|
model = Reimbursement
|
|
fields = '__all__'
|
|
|
|
def get_other_attachements(self, obj):
|
|
attachments = []
|
|
for attachment in obj.other_attachments.all():
|
|
try:
|
|
attachments.append(attachment.attachment.url)
|
|
except :
|
|
pass
|
|
return attachments
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
exclude_fields = []
|
|
# Get type from data or instance
|
|
instance_type = getattr(self.instance, 'type', None)
|
|
|
|
if instance_type == "reimbursement":
|
|
exclude_fields.extend(
|
|
["leave_type_id", "cfd_to_encash", "ad_to_encash", "bonus_to_encash"])
|
|
elif instance_type == "leave_encashment":
|
|
exclude_fields.extend(["attachment", "amount", "bonus_to_encash"])
|
|
elif instance_type == "bonus_encashment":
|
|
exclude_fields.extend(
|
|
["attachment", "amount", "leave_type_id", "cfd_to_encash", "ad_to_encash"])
|
|
|
|
# Remove excluded fields from serializer fields
|
|
for field in exclude_fields:
|
|
self.fields.pop(field, None)
|
|
|
|
def get_encashable_leaves(self, employee):
|
|
leaves = LeaveType.objects.filter(
|
|
employee_available_leave__employee_id=employee,
|
|
employee_available_leave__total_leave_days__gte=1,
|
|
is_encashable=True,
|
|
)
|
|
return leaves
|
|
|
|
def validate(self, data):
|
|
try:
|
|
employee_id = self.instance.employee_id
|
|
type = self.instance.type
|
|
leave_type_id = self.instance.leave_type_id
|
|
except:
|
|
employee_id = data["employee_id"]
|
|
type = data["type"]
|
|
leave_type_id = data["leave_type_id"] if data.get("leave_type_id",None) else None
|
|
|
|
available_points = BonusPoint.objects.filter(
|
|
employee_id=employee_id
|
|
).first()
|
|
if type == "bonus_encashment":
|
|
try:
|
|
bonus_to_encash = self.instance.bonus_to_encash
|
|
except:
|
|
bonus_to_encash = data["bonus_to_encash"]
|
|
|
|
if available_points.points < bonus_to_encash:
|
|
raise serializers.ValidationError(
|
|
{"bonus_to_encash": "Not enough bonus points to redeem"}
|
|
)
|
|
if bonus_to_encash <= 0:
|
|
raise serializers.ValidationError(
|
|
{
|
|
"bonus_to_encash": "Points must be greater than zero to redeem."
|
|
}
|
|
)
|
|
if type == "leave_encashment":
|
|
leave_type_id = leave_type_id
|
|
encashable_leaves = self.get_encashable_leaves(employee_id)
|
|
if (leave_type_id is None) or (leave_type_id not in encashable_leaves):
|
|
raise serializers.ValidationError(
|
|
{"leave_type_id": "This leave type is not encashable"}
|
|
)
|
|
|
|
return data
|
|
|
|
def save(self, **kwargs):
|
|
multiple_attachment_ids = []
|
|
request_files = self.context['request'].FILES
|
|
attachments = request_files.getlist("attachment")
|
|
if attachments:
|
|
for attachment in attachments:
|
|
file_instance = ReimbursementMultipleAttachment()
|
|
file_instance.attachment = attachment
|
|
file_instance.save()
|
|
multiple_attachment_ids.append(file_instance.pk)
|
|
|
|
instance = super().save()
|
|
instance.other_attachments.add(*multiple_attachment_ids)
|
|
|
|
return super().save(**kwargs)
|
|
|
|
class TaxBracketSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
fields = '__all__'
|
|
model = TaxBracket
|