একটি বড় গল্প আকারে শ্রমিকের শিফট এবং উপস্থিতি ব্যবস্থাপনা:
একটি কোম্পানির একজন অ্যাডমিনকে কল্পনা করি, তার নাম সোহেল। সোহেল অ্যাডমিন হিসাবে একটি সফটওয়্যার ব্যবহারের মাধ্যমে তার কোম্পানির শ্রমিকদের শিফট এবং উপস্থিতি পরিচালনা করে থাকেন। এই সফটওয়্যারটি ডেটাবেস ভিত্তিক এবং এতে শ্রমিকদের শিফট, উপস্থিতি এবং শিফট পরিবর্তন সহ বেশ কিছু গুরুত্বপূর্ণ ফিচার রয়েছে।
ধাপ ১: সোহেল কোম্পানিতে লগইন করে
প্রথমেই, সোহেল কোম্পানির অ্যাডমিন হিসাবে লগইন করে তার ড্যাশবোর্ডে প্রবেশ করে। এপ্লিকেশনটি সিকিউরিটি রক্ষার জন্য CustomUser মডেল ব্যবহার করে থাকে, যেখানে সোহেল ইমেইল ও পাসওয়ার্ড দিয়ে লগইন করেন। এই মডেলে email, mobileNo, এবং company ফিল্ডগুলো সোহেলের প্রোফাইলে সংযুক্ত রয়েছে।
class CustomUser(AbstractUser):
email = models.EmailField(unique=True, validators=[EmailValidator()])
mobileNo = models.CharField(
max_length=15,
blank=True,
null=True,
validators=[
RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Mobile number must be in the format: '+999999999'. Up to 15 digits allowed.")
]
)
company = models.ForeignKey('Company', on_delete=models.SET_NULL, related_name='employees', null=True, blank=True)
is_company_active = models.BooleanField(default=True)
# Setting email as username field
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
ধাপ ২: কোম্পানির শ্রমিক নিবন্ধন
সোহেল এখন শ্রমিকদের প্রোফাইল তৈরি করতে শুরু করে। তিনি নতুন শ্রমিক রেজিস্টার করেন, যেখানে Employee মডেলে শ্রমিকের তথ্য যেমন employee_id, department, position, এবং contact_number সংরক্ষণ করা হয়।
class Employee(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='company_employees', verbose_name=_("Company"), null=True, blank=True)
employee_id = models.CharField(max_length=20, verbose_name=_("Employee ID"))
department = models.CharField(max_length=50, null=True, blank=True, verbose_name=_("Department name"))
position = models.CharField(max_length=50, null=True, blank=True, verbose_name=_("Position title"))
contact_number = models.CharField(max_length=15, null=True, blank=True, verbose_name=_("Contact number"))
date_of_joining = models.DateField(null=True, blank=True, verbose_name=_("Date of joining"))
ধাপ ৩: শিফট তৈরি
এখন সোহেল নতুন শিফট তৈরি করে। প্রতিটি শিফটের নির্দিষ্ট start_time এবং end_time থাকে। Shift মডেলে শিফটের স্ট্যাটাস এবং সময় সংরক্ষণ করা হয়।
class Shift(models.Model):
name = models.CharField(max_length=50)
start_time = models.TimeField()
end_time = models.TimeField()
break_duration = models.DurationField(null=True, blank=True)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='shifts', null=True)
status = models.CharField(max_length=10, choices=[('ACTIVE', 'Active'), ('INACTIVE', 'Inactive')], default='ACTIVE')
ধাপ ৪: শ্রমিকদের সিডিউল করা
প্রত্যেক শ্রমিককে একটি নির্দিষ্ট শিফটে কাজের দিন অনুযায়ী সিডিউল করা হয়। Schedule মডেল দিয়ে প্রতিটি শ্রমিকের জন্য কোন শিফটে তারা কোন দিনে কাজ করবেন তা নির্ধারণ করা হয়।
class Schedule(models.Model):
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
shift = models.ForeignKey(Shift, on_delete=models.CASCADE)
workdays = models.ManyToManyField(Workday)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='shifts', null=True)
ধাপ ৫: অস্থায়ী শিফট তৈরি
কখনও কখনও কিছু শ্রমিককে নির্দিষ্ট দিনে নির্দিষ্ট শিফটে কাজ করতে হতে পারে যা পূর্ব নির্ধারিত শিফট নয়। এদের অস্থায়ী শিফট হিসাবে সংরক্ষণ করা হয়। TemporaryShift মডেল দিয়ে নির্দিষ্ট তারিখের জন্য অস্থায়ী শিফট সংরক্ষণ করা হয়।
class TemporaryShift(models.Model):
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
shift = models.ForeignKey(Shift, on_delete=models.CASCADE)
date = models.DateField() # অস্থায়ী শিফটের নির্দিষ্ট তারিখ
company = models.ForeignKey(Company, on_delete=models.CASCADE)
কয়েকটি শ্রমিকের জন্য অস্থায়ী শিফট যুক্ত করা
অ্যাডমিন যখন একসাথে কয়েকজন শ্রমিককে নির্দিষ্ট দিনে অস্থায়ী শিফট যুক্ত করতে চাইবেন, তখন তারা এটি Django Admin অথবা API এর মাধ্যমে করতে পারবেন।
নিচে একটি উদাহরণ API এর মাধ্যমে:
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import TemporaryShift, Employee, Shift
class AssignTemporaryShiftAPIView(APIView):
def post(self, request):
employees = request.data.get('employees') # শ্রমিকদের ID
shift_id = request.data.get('shift_id') # শিফট ID
date = request.data.get('date') # দিন
shift = Shift.objects.get(id=shift_id)
for employee_id in employees:
employee = Employee.objects.get(id=employee_id)
TemporaryShift.objects.create(employee=employee, shift=shift, date=date)
return Response({"message": "Temporary shifts assigned successfully"}, status=status.HTTP_201_CREATED)
একটি নির্দিষ্ট ডেট রেঞ্জের (যেমন ১৫ অক্টোবর ২০২৪ থেকে ২০ অক্টোবর ২০২৪ পর্যন্ত) মধ্যে নির্দিষ্ট শ্রমিকদের অস্থায়ী শিফট রেকর্ড করা। এখানে প্রতিটি দিন (১৫ অক্টোবর থেকে ২০ অক্টোবর) এর জন্য শ্রমিকদের শিফট রেকর্ড হবে। এই কাজটি করার জন্য আমরা for loop ব্যবহার করে প্রতিটি দিনের জন্য অস্থায়ী শিফট তৈরি করতে পারি।
কোড উদাহরণ:
আমরা API তৈরি করবো, যেখানে অ্যাডমিন শ্রমিকের তালিকা, শিফট ID, এবং ডেট রেঞ্জ (start_date এবং end_date) দিয়ে রিকোয়েস্ট পাঠাতে পারবে, এবং প্রতিটি দিনের জন্য শিফট রেকর্ড তৈরি হবে।
API View:
from datetime import timedelta
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import TemporaryShift, Employee, Shift
class AssignTemporaryShiftForDateRangeAPIView(APIView):
"""
এই API এর মাধ্যমে নির্দিষ্ট ডেট রেঞ্জের মধ্যে একাধিক শ্রমিককে একটি অস্থায়ী শিফট অ্যাসাইন করা হবে।
"""
def post(self, request):
# শ্রমিকদের ID এর লিস্ট
employee_ids = request.data.get('employees') # ['1', '2', '3'] এরকম
shift_id = request.data.get('shift_id') # নির্দিষ্ট শিফট ID
start_date = request.data.get('start_date') # ডেট রেঞ্জের শুরুর দিন (YYYY-MM-DD format)
end_date = request.data.get('end_date') # ডেট রেঞ্জের শেষের দিন (YYYY-MM-DD format)
# শিফট আইডি দিয়ে শিফট খুঁজে বের করা
shift = Shift.objects.get(id=shift_id)
# প্রতিটি শ্রমিকের জন্য অস্থায়ী শিফট রেকর্ড তৈরি করা
for employee_id in employee_ids:
employee = Employee.objects.get(id=employee_id)
# স্টার্ট ডেট থেকে এন্ড ডেট পর্যন্ত প্রতিটি দিনের জন্য শিফট রেকর্ড করা
current_date = start_date
while current_date <= end_date:
# যদি ইতিমধ্যেই ওই দিন ওই শ্রমিকের শিফট রেকর্ড না থাকে, তবে নতুন রেকর্ড তৈরি করা
if not TemporaryShift.objects.filter(employee=employee, date=current_date).exists():
TemporaryShift.objects.create(
employee=employee,
shift=shift,
date=current_date
)
# দিনটি ১ দিন করে বাড়ানো
current_date += timedelta(days=1)
return Response({"message": "Temporary shifts assigned successfully for the date range"}, status=status.HTTP_201_CREATED)
কিভাবে API কাজ করবে:
১. Input: আপনি শ্রমিকদের ID এর একটি লিস্ট, একটি শিফট ID, এবং একটি ডেট রেঞ্জ (start_date এবং end_date) দিবেন। ২. Output: প্রতিটি শ্রমিকের জন্য ডেট রেঞ্জের মধ্যে প্রতিটি দিনের অস্থায়ী শিফট রেকর্ড হবে। ৩. লজিক:
- শুরুর দিন থেকে শেষ দিন পর্যন্ত প্রতিটি দিন লুপের মাধ্যমে বের করা হবে।
- যদি ওই দিন কোনো শিফট রেকর্ড না থাকে, তবে নতুন অস্থায়ী শিফট রেকর্ড তৈরি করা হবে।
উদাহরণ রিকোয়েস্ট (API Call):
আপনার API এ এই রিকোয়েস্ট করতে পারেন:
POST /api/assign-temporary-shift-date-range/
{
"employees": [1, 2, 3], // শ্রমিকদের ID
"shift_id": 1, // শিফটের ID
"start_date": "2024-10-15", // শুরুর দিন
"end_date": "2024-10-20" // শেষ দিন
}
প্রতিক্রিয়া (Response):
{
"message": "Temporary shifts assigned successfully for the date range"
}
ধাপ ৬: উপস্থিতি লগ
এখন শ্রমিকরা যখন কাজের জন্য উপস্থিত হন, তখন উপস্থিতির ডাটা AttendanceLog মডেলে সংরক্ষণ করা হয়। এটি শ্রমিকের punch_datetime, in_out_status, এবং অন্যান্য তথ্য যেমন device, location, এবং work_code সংরক্ষণ করে।
class AttendanceLog(models.Model):
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='attendance_logs', verbose_name=_("Employee"))
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='attendance_logs', null=True)
punch_datetime = models.DateTimeField(default=timezone.now, verbose_name=_("Date & Time of Punch"))
in_out_status = models.CharField(max_length=20, choices=[('IN', 'Check-In'), ('OUT', 'Check-Out')], default='IN')
device = models.ForeignKey(Device, on_delete=models.CASCADE, null=True, blank=True)
punch_mode = models.CharField(max_length=10, choices=[('AUTO', 'Auto'), ('MANUAL', 'Manual')], default='AUTO')
ধাপ ৭: উপস্থিতি দেখার পদ্ধতি
এখন সোহেল যদি কোনো শ্রমিকের উপস্থিতি দেখতে চান, তাহলে তাকে শুধু সেই শ্রমিকের আইডি দিয়ে নির্দিষ্ট দিনের রেকর্ড দেখতে হবে। যদি ওই দিনের জন্য অস্থায়ী শিফট থাকে, তাহলে সেটা দেখানো হবে। আর যদি না থাকে, তাহলে শ্রমিকের সিডিউল করা শিফট দেখানো হবে।
def get_employee_attendance(employee_id, start_date, end_date, company):
attendance_logs = AttendanceLog.objects.filter(
employee__employee_id=employee_id,
company=company,
punch_datetime__date__range=[start_date, end_date]
)
for log in attendance_logs:
# Check if there is a temporary shift for the employee on that date
temp_shift = TemporaryShift.objects.filter(employee=log.employee, date=log.punch_datetime.date(), company=company).first()
if temp_shift:
shift_info = temp_shift.shift
else:
# Get the default scheduled shift
shift_info = log.employee.schedule_set.first().shift
print(f"Date: {log.punch_datetime.date()}, Shift: {shift_info.name}")