2023 lines
73 KiB
Python
2023 lines
73 KiB
Python
"""
|
|
views.py
|
|
|
|
This module contains the view functions for handling HTTP requests and rendering
|
|
responses in your application.
|
|
|
|
Each view function corresponds to a specific URL route and performs the necessary
|
|
actions to handle the request, process data, and generate a response.
|
|
|
|
This module is part of the recruitment project and is intended to
|
|
provide the main entry points for interacting with the application's functionality.
|
|
"""
|
|
|
|
import calendar
|
|
import json
|
|
import contextlib
|
|
from datetime import datetime, timedelta
|
|
from datetime import date
|
|
import pandas as pd
|
|
from urllib.parse import parse_qs
|
|
from django.shortcuts import render, redirect
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.utils.translation import gettext as __
|
|
from django.contrib import messages
|
|
from django.core.paginator import Paginator
|
|
from django.db.models import ProtectedError
|
|
from django.http import HttpResponseRedirect, HttpResponse, JsonResponse
|
|
from django.views.decorators.http import require_http_methods
|
|
from employee.models import Employee
|
|
from horilla.decorators import (
|
|
permission_required,
|
|
login_required,
|
|
hx_request_required,
|
|
manager_can_enter,
|
|
)
|
|
from base.methods import closest_numbers, export_data, get_pagination
|
|
from base.methods import get_key_instances
|
|
from base.models import EmployeeShiftSchedule
|
|
from base.methods import filtersubordinates, choosesubordinates
|
|
from leave.models import WEEK_DAYS, CompanyLeave, Holiday
|
|
from notifications.signals import notify
|
|
from attendance.views.handle_attendance_errors import handle_attendance_errors
|
|
from attendance.views.process_attendance_data import process_attendance_data
|
|
from attendance.filters import (
|
|
AttendanceFilters,
|
|
AttendanceOverTimeFilter,
|
|
LateComeEarlyOutFilter,
|
|
AttendanceActivityFilter,
|
|
)
|
|
from attendance.forms import (
|
|
AttendanceActivityExportForm,
|
|
AttendanceForm,
|
|
AttendanceOverTimeExportForm,
|
|
AttendanceOverTimeForm,
|
|
AttendanceValidationConditionForm,
|
|
AttendanceUpdateForm,
|
|
AttendanceExportForm,
|
|
AttendancerequestCommentForm,
|
|
GraceTimeForm,
|
|
LateComeEarlyOutExportForm,
|
|
)
|
|
|
|
from attendance.models import (
|
|
Attendance,
|
|
AttendanceActivity,
|
|
AttendanceGeneralSetting,
|
|
AttendanceOverTime,
|
|
AttendanceLateComeEarlyOut,
|
|
AttendanceValidationCondition,
|
|
AttendancerequestComment,
|
|
AttendancerequestFile,
|
|
GraceTime,
|
|
)
|
|
from attendance.filters import (
|
|
AttendanceReGroup,
|
|
AttendanceOvertimeReGroup,
|
|
LateComeEarlyOutReGroup,
|
|
AttendanceActivityReGroup,
|
|
)
|
|
from payroll.models.models import WorkRecord
|
|
|
|
|
|
# Create your views here.
|
|
|
|
|
|
def intersection_list(list1, list2):
|
|
"""
|
|
This method is used to intersect two list
|
|
"""
|
|
return [value for value in list1 if value in list2]
|
|
|
|
|
|
def format_time(seconds):
|
|
"""
|
|
this method is used to formate seconds to H:M and return it
|
|
args:
|
|
seconds : seconds
|
|
"""
|
|
|
|
hour = int(seconds // 3600)
|
|
minutes = int((seconds % 3600) // 60)
|
|
seconds = int((seconds % 3600) % 60)
|
|
return f"{hour:02d}:{minutes:02d}"
|
|
|
|
|
|
def strtime_seconds(time):
|
|
"""
|
|
this method is used reconvert time in H:M formate string back to seconds and return it
|
|
args:
|
|
time : time in H:M format
|
|
"""
|
|
|
|
ftr = [3600, 60, 1]
|
|
return sum(a * b for a, b in zip(ftr, map(int, time.split(":"))))
|
|
|
|
|
|
def is_reportingmanger(request, instance):
|
|
"""
|
|
if the instance have employee id field then you can use this method to know the
|
|
request user employee is the reporting manager of the instance
|
|
args :
|
|
request : request
|
|
instance : an object or instance of any model contain employee_id foreign key field
|
|
"""
|
|
|
|
manager = request.user.employee_get
|
|
try:
|
|
employee_workinfo_manager = (
|
|
instance.employee_id.employee_work_info.reporting_manager_id
|
|
)
|
|
except Exception:
|
|
return HttpResponse("This Employee Dont Have any work information")
|
|
return manager == employee_workinfo_manager
|
|
|
|
|
|
def attendance_validate(attendance):
|
|
"""
|
|
This method is is used to check condition for at work in AttendanceValidationCondition
|
|
model instance it return true if at work is smaller than condition
|
|
args:
|
|
attendance : attendance object
|
|
"""
|
|
|
|
conditions = AttendanceValidationCondition.objects.all()
|
|
# Set the default condition for 'at work' to 9:00 AM
|
|
condition_for_at_work = strtime_seconds("09:00")
|
|
if conditions.exists():
|
|
condition_for_at_work = strtime_seconds(conditions[0].validation_at_work)
|
|
at_work = strtime_seconds(attendance.attendance_worked_hour)
|
|
return condition_for_at_work >= at_work
|
|
|
|
|
|
def attendance_day_checking(attendance_date, minimum_hour):
|
|
# Convert the string to a datetime object
|
|
attendance_datetime = datetime.strptime(attendance_date, "%Y-%m-%d")
|
|
|
|
# Extract name of the day
|
|
attendance_day = attendance_datetime.strftime("%A")
|
|
|
|
# Taking all holidays into a list
|
|
leaves = []
|
|
holidays = Holiday.objects.all()
|
|
for holi in holidays:
|
|
start_date = holi.start_date
|
|
end_date = holi.end_date
|
|
|
|
# Convert start_date and end_date to datetime objects
|
|
start_date = datetime.strptime(str(start_date), "%Y-%m-%d")
|
|
end_date = datetime.strptime(str(end_date), "%Y-%m-%d")
|
|
|
|
# Add dates in between start date and end date including both
|
|
current_date = start_date
|
|
while current_date <= end_date:
|
|
leaves.append(current_date.strftime("%Y-%m-%d"))
|
|
current_date += timedelta(days=1)
|
|
|
|
# Checking attendance date is in holiday list, if found making the minimum hour to 00:00
|
|
for leave in leaves:
|
|
if str(leave) == str(attendance_date):
|
|
minimum_hour = "00:00"
|
|
break
|
|
|
|
# Making a dictonary contains week day value and leave day pairs
|
|
company_leaves = {}
|
|
company_leave = CompanyLeave.objects.all()
|
|
for com_leave in company_leave:
|
|
a = dict(WEEK_DAYS).get(com_leave.based_on_week_day)
|
|
b = com_leave.based_on_week
|
|
company_leaves[b] = a
|
|
|
|
# Checking the attendance date is in which week
|
|
week_in_month = str(((attendance_datetime.day - 1) // 7 + 1) - 1)
|
|
|
|
# Checking the attendance date is in the company leave or not
|
|
for pairs in company_leaves.items():
|
|
# For all weeks based_on_week is None
|
|
if str(pairs[0]) == "None":
|
|
if str(pairs[1]) == str(attendance_day):
|
|
minimum_hour = "00:00"
|
|
break
|
|
# Checking with based_on_week and attendance_date week
|
|
if str(pairs[0]) == week_in_month:
|
|
if str(pairs[1]) == str(attendance_day):
|
|
minimum_hour = "00:00"
|
|
break
|
|
return minimum_hour
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.add_attendance")
|
|
def attendance_create(request):
|
|
"""
|
|
This method is used to render attendance create form and save if it is valid
|
|
"""
|
|
form = AttendanceForm()
|
|
form = choosesubordinates(request, form, "attendance.add_attendance")
|
|
if request.method == "POST":
|
|
form = AttendanceForm(request.POST)
|
|
form = choosesubordinates(request, form, "attendance.add_attendance")
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _("Attendance added."))
|
|
response = render(
|
|
request, "attendance/attendance/form.html", {"form": form}
|
|
)
|
|
return HttpResponse(
|
|
response.content.decode("utf-8") + "<script>location.reload();</script>"
|
|
)
|
|
return render(request, "attendance/attendance/form.html", {"form": form})
|
|
|
|
|
|
def get_record_per_page():
|
|
"""
|
|
This method will return the record per page count
|
|
"""
|
|
return 50
|
|
|
|
|
|
def paginator_qry(qryset, page_number):
|
|
"""
|
|
This method is used to paginate queryset
|
|
"""
|
|
paginator = Paginator(qryset, get_pagination())
|
|
qryset = paginator.get_page(page_number)
|
|
return qryset
|
|
|
|
|
|
def attendance_excel(_request):
|
|
"""
|
|
Generate an empty Excel template for attendance data with predefined columns.
|
|
|
|
Returns:
|
|
HttpResponse: An HTTP response containing an empty Excel template with predefined columns.
|
|
"""
|
|
try:
|
|
columns = [
|
|
"Badge ID",
|
|
"Shift",
|
|
"Work type",
|
|
"Attendance date",
|
|
"Check-in date",
|
|
"Check-in",
|
|
"Check-out date",
|
|
"Check-out",
|
|
"Worked hour",
|
|
"Minimum hour",
|
|
]
|
|
data_frame = pd.DataFrame(columns=columns)
|
|
response = HttpResponse(content_type="application/ms-excel")
|
|
response["Content-Disposition"] = 'attachment; filename="my_excel_file.xlsx"'
|
|
data_frame.to_excel(response, index=False)
|
|
return response
|
|
except Exception as exception:
|
|
return HttpResponse(exception)
|
|
|
|
|
|
def attendance_import(request):
|
|
"""
|
|
Save the import of attendance data from an uploaded Excel file, validate the data,
|
|
and return an Excel file with error details if validation fails for anyone
|
|
of the attendance data.
|
|
|
|
Parameters:
|
|
request (HttpRequest): The HTTP request object containing the uploaded Excel file.
|
|
|
|
Returns:
|
|
HttpResponse or redirect: An HTTP response with an Excel file containing error details
|
|
if validation fails, or a redirect to the attendance view if successful.
|
|
"""
|
|
if request.method == "POST":
|
|
file = request.FILES["attendance_import"]
|
|
data_frame = pd.read_excel(file)
|
|
attendance_dicts = data_frame.to_dict("records")
|
|
attendance_import = process_attendance_data(attendance_dicts)
|
|
|
|
if attendance_import:
|
|
error_data = handle_attendance_errors(attendance_import)
|
|
data_frame = pd.DataFrame(error_data, columns=error_data.keys())
|
|
response = HttpResponse(content_type="application/ms-excel")
|
|
response["Content-Disposition"] = 'attachment; filename="ImportError.xlsx"'
|
|
data_frame.to_excel(response, index=False)
|
|
return response
|
|
|
|
return redirect(attendance_view)
|
|
return redirect(attendance_view)
|
|
|
|
|
|
@login_required
|
|
def attendance_export(request):
|
|
return export_data(
|
|
request=request,
|
|
model=Attendance,
|
|
filter_class=AttendanceFilters,
|
|
form_class=AttendanceExportForm,
|
|
file_name="Attendance_export",
|
|
)
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.view_attendance")
|
|
def attendance_view(request):
|
|
"""
|
|
This method is used to view attendances.
|
|
"""
|
|
previous_data = request.GET.urlencode()
|
|
form = AttendanceForm()
|
|
export_form = AttendanceExportForm()
|
|
condition = AttendanceValidationCondition.objects.first()
|
|
minot = strtime_seconds("00:00")
|
|
if condition is not None and condition.minimum_overtime_to_approve is not None:
|
|
minot = strtime_seconds(condition.minimum_overtime_to_approve)
|
|
validate_attendances = Attendance.objects.filter(
|
|
attendance_validated=False, employee_id__is_active=True
|
|
)
|
|
attendances = Attendance.objects.filter(
|
|
attendance_validated=True, employee_id__is_active=True
|
|
)
|
|
ot_attendances = Attendance.objects.filter(
|
|
overtime_second__gte=minot,
|
|
attendance_validated=True,
|
|
employee_id__is_active=True,
|
|
)
|
|
filter_obj = AttendanceFilters(request.GET, queryset=attendances)
|
|
attendances = filtersubordinates(
|
|
request, filter_obj.qs, "attendance.view_attendance"
|
|
)
|
|
validate_attendances = AttendanceFilters(
|
|
request.GET, queryset=validate_attendances
|
|
).qs
|
|
validate_attendances = filtersubordinates(
|
|
request, validate_attendances, "attendance.view_attendance"
|
|
)
|
|
ot_attendances = AttendanceFilters(request.GET, queryset=ot_attendances).qs
|
|
ot_attendances = filtersubordinates(
|
|
request, ot_attendances, "attendance.view_attendance"
|
|
)
|
|
check_attendance = Attendance.objects.all()
|
|
if check_attendance.exists():
|
|
template = "attendance/attendance/attendance_view.html"
|
|
else:
|
|
template = "attendance/attendance/attendance_empty.html"
|
|
validate_attendances_ids = json.dumps(
|
|
[
|
|
instance.id
|
|
for instance in paginator_qry(
|
|
validate_attendances, request.GET.get("vpage")
|
|
).object_list
|
|
]
|
|
)
|
|
ot_attendances_ids = json.dumps(
|
|
[
|
|
instance.id
|
|
for instance in paginator_qry(
|
|
ot_attendances, request.GET.get("opage")
|
|
).object_list
|
|
]
|
|
)
|
|
attendances_ids = json.dumps(
|
|
[
|
|
instance.id
|
|
for instance in paginator_qry(
|
|
attendances, request.GET.get("page")
|
|
).object_list
|
|
]
|
|
)
|
|
return render(
|
|
request,
|
|
template,
|
|
{
|
|
"form": form,
|
|
"export_form": export_form,
|
|
"validate_attendances": paginator_qry(
|
|
validate_attendances, request.GET.get("vpage")
|
|
),
|
|
"attendances": paginator_qry(attendances, request.GET.get("page")),
|
|
"overtime_attendances": paginator_qry(
|
|
ot_attendances, request.GET.get("opage")
|
|
),
|
|
"validate_attendances_ids": validate_attendances_ids,
|
|
"ot_attendances_ids": ot_attendances_ids,
|
|
"attendances_ids": attendances_ids,
|
|
"f": filter_obj,
|
|
"export": AttendanceFilters(queryset=Attendance.objects.all()),
|
|
"pd": previous_data,
|
|
"gp_fields": AttendanceReGroup.fields,
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.change_attendance")
|
|
def attendance_update(request, obj_id):
|
|
"""
|
|
This method render form to update attendance and save if the form is valid
|
|
args:
|
|
obj_id : attendance id
|
|
"""
|
|
attendance = Attendance.objects.get(id=obj_id)
|
|
form = AttendanceUpdateForm(
|
|
instance=attendance,
|
|
)
|
|
form = choosesubordinates(request, form, "attendance.change_attendance")
|
|
if request.method == "POST":
|
|
form = AttendanceUpdateForm(request.POST, instance=attendance)
|
|
form = choosesubordinates(request, form, "attendance.change_attendance")
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _("Attendance Updated."))
|
|
urlencode = request.GET.urlencode()
|
|
modified_url = f"/attendance/attendance-view/?{urlencode}"
|
|
return HttpResponse(
|
|
f"""
|
|
<script>
|
|
window.location.reload();
|
|
</script>
|
|
"""
|
|
)
|
|
return render(
|
|
request,
|
|
"attendance/attendance/update_form.html",
|
|
{
|
|
"form": form,
|
|
"urlencode": request.GET.urlencode(),
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_attendance")
|
|
@require_http_methods(["POST"])
|
|
def attendance_delete(request, obj_id):
|
|
"""
|
|
This method is used to delete attendance.
|
|
args:
|
|
obj_id : attendance id
|
|
"""
|
|
try:
|
|
attendance = Attendance.objects.get(id=obj_id)
|
|
month = attendance.attendance_date
|
|
month = month.strftime("%B").lower()
|
|
overtime = attendance.employee_id.employee_overtime.filter(month=month).last()
|
|
if overtime is not None:
|
|
if attendance.attendance_overtime_approve:
|
|
# Subtract overtime of this attendance
|
|
total_overtime = strtime_seconds(overtime.overtime)
|
|
attendance_overtime_seconds = strtime_seconds(
|
|
attendance.attendance_overtime
|
|
)
|
|
if total_overtime > attendance_overtime_seconds:
|
|
total_overtime = total_overtime - attendance_overtime_seconds
|
|
else:
|
|
total_overtime = attendance_overtime_seconds - total_overtime
|
|
overtime.overtime = format_time(total_overtime)
|
|
overtime.save()
|
|
try:
|
|
attendance.delete()
|
|
messages.success(request, _("Attendance deleted."))
|
|
except ProtectedError as e:
|
|
model_verbose_names_set = set()
|
|
for obj in e.protected_objects:
|
|
model_verbose_names_set.add(__(obj._meta.verbose_name.capitalize()))
|
|
model_names_str = ", ".join(model_verbose_names_set)
|
|
messages.error(
|
|
request,
|
|
_(
|
|
("An attendance entry for {} already exists.").format(
|
|
model_names_str
|
|
)
|
|
),
|
|
)
|
|
except (Attendance.DoesNotExist, OverflowError):
|
|
messages.error(request, _("Attendance Does not exists.."))
|
|
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
|
|
|
|
|
@require_http_methods(["POST"])
|
|
def attendance_bulk_delete(request):
|
|
"""
|
|
This method is used to delete bulk of attendances
|
|
"""
|
|
ids = request.POST["ids"]
|
|
ids = json.loads(ids)
|
|
for attendance_id in ids:
|
|
try:
|
|
attendance = Attendance.objects.get(id=attendance_id)
|
|
month = attendance.attendance_date
|
|
month = month.strftime("%B").lower()
|
|
overtime = attendance.employee_id.employee_overtime.filter(
|
|
month=month
|
|
).last()
|
|
if overtime is not None:
|
|
if attendance.attendance_overtime_approve:
|
|
# Subtract overtime of this attendance
|
|
total_overtime = strtime_seconds(overtime.overtime)
|
|
attendance_overtime_seconds = strtime_seconds(
|
|
attendance.attendance_overtime
|
|
)
|
|
if total_overtime > attendance_overtime_seconds:
|
|
total_overtime = total_overtime - attendance_overtime_seconds
|
|
else:
|
|
total_overtime = attendance_overtime_seconds - total_overtime
|
|
overtime.overtime = format_time(total_overtime)
|
|
overtime.save()
|
|
try:
|
|
attendance.delete()
|
|
messages.success(request, _("Attendance Deleted"))
|
|
|
|
except ProtectedError as e:
|
|
model_verbose_names_set = set()
|
|
for obj in e.protected_objects:
|
|
model_verbose_names_set.add(
|
|
__(obj._meta.verbose_name.capitalize())
|
|
)
|
|
model_names_str = ", ".join(model_verbose_names_set)
|
|
messages.error(
|
|
request,
|
|
_(
|
|
("An attendance entry for {} already exists.").format(
|
|
model_names_str
|
|
)
|
|
),
|
|
)
|
|
except Attendance.DoesNotExist:
|
|
messages.error(request, _("Attendance not found."))
|
|
|
|
return JsonResponse({"message": "Success"})
|
|
|
|
|
|
@login_required
|
|
def view_my_attendance(request):
|
|
"""
|
|
This method is used to view self attendances of employee
|
|
"""
|
|
user = request.user
|
|
try:
|
|
employee = user.employee_get
|
|
except:
|
|
return redirect("/employee/employee-profile")
|
|
employee = user.employee_get
|
|
employee_attendances = employee.employee_attendances.all()
|
|
filter = AttendanceFilters()
|
|
if employee_attendances.exists():
|
|
template = "attendance/own_attendance/view_own_attendances.html"
|
|
else:
|
|
template = "attendance/own_attendance/own_empty.html"
|
|
attendances_ids = json.dumps(
|
|
[
|
|
instance.id
|
|
for instance in paginator_qry(
|
|
employee_attendances, request.GET.get("page")
|
|
).object_list
|
|
]
|
|
)
|
|
return render(
|
|
request,
|
|
template,
|
|
{
|
|
"attendances": paginator_qry(employee_attendances, request.GET.get("page")),
|
|
"attendances_ids": attendances_ids,
|
|
"f": filter,
|
|
"gp_fields": AttendanceReGroup.fields,
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.add_attendanceovertime")
|
|
def attendance_overtime_create(request):
|
|
"""
|
|
This method is used to render overtime creating form and save if the form is valid
|
|
"""
|
|
form = AttendanceOverTimeForm()
|
|
form = choosesubordinates(request, form, "attendance.add_attendanceovertime")
|
|
if request.method == "POST":
|
|
form = AttendanceOverTimeForm(request.POST)
|
|
form = choosesubordinates(request, form, "attendance.add_attendanceovertime")
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _("Attendance account added."))
|
|
response = render(
|
|
request, "attendance/attendance_account/form.html", {"form": form}
|
|
)
|
|
return HttpResponse(
|
|
response.content.decode("utf-8") + "<script>location.reload();</script>"
|
|
)
|
|
return render(request, "attendance/attendance_account/form.html", {"form": form})
|
|
|
|
|
|
@login_required
|
|
def attendance_overtime_view(request):
|
|
"""
|
|
This method is used to view attendance account or overtime account.
|
|
"""
|
|
previous_data = request.GET.urlencode()
|
|
filter_obj = AttendanceOverTimeFilter(request.GET)
|
|
if filter_obj.qs.exists():
|
|
template = "attendance/attendance_account/attendance_overtime_view.html"
|
|
else:
|
|
template = "attendance/attendance_account/overtime_empty.html"
|
|
self_account = filter_obj.qs.filter(employee_id__employee_user_id=request.user)
|
|
accounts = filtersubordinates(
|
|
request, filter_obj.qs, "attendance.view_attendanceovertime"
|
|
)
|
|
accounts = accounts | self_account
|
|
accounts = accounts.distinct()
|
|
form = AttendanceOverTimeForm()
|
|
form = choosesubordinates(request, form, "attendance.add_attendanceovertime")
|
|
export_obj = AttendanceOverTimeFilter()
|
|
export_fields = AttendanceOverTimeExportForm()
|
|
data_dict = parse_qs(previous_data)
|
|
get_key_instances(AttendanceOverTime, data_dict)
|
|
return render(
|
|
request,
|
|
template,
|
|
{
|
|
"accounts": paginator_qry(accounts, request.GET.get("page")),
|
|
"form": form,
|
|
"pd": previous_data,
|
|
"f": filter_obj,
|
|
"export_obj": export_obj,
|
|
"export_fields": export_fields,
|
|
"gp_fields": AttendanceOvertimeReGroup.fields,
|
|
"filter_dict": data_dict,
|
|
},
|
|
)
|
|
|
|
|
|
def attendance_account_export(request):
|
|
return export_data(
|
|
request=request,
|
|
model=AttendanceOverTime,
|
|
filter_class=AttendanceOverTimeFilter,
|
|
form_class=AttendanceOverTimeExportForm,
|
|
file_name="Attendance_Account",
|
|
)
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.change_attendanceovertime")
|
|
@hx_request_required
|
|
def attendance_overtime_update(request, obj_id):
|
|
"""
|
|
This method is used to update attendance overtime and save if the forms is valid
|
|
args:
|
|
obj_id : attendance overtime id
|
|
"""
|
|
overtime = AttendanceOverTime.objects.get(id=obj_id)
|
|
form = AttendanceOverTimeForm(instance=overtime)
|
|
form = choosesubordinates(request, form, "attendance.change_attendanceovertime")
|
|
if request.method == "POST":
|
|
form = AttendanceOverTimeForm(request.POST, instance=overtime)
|
|
form = choosesubordinates(request, form, "attendance.change_attendanceovertime")
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _("Attendance account updated successfully."))
|
|
response = render(
|
|
request,
|
|
"attendance/attendance_account/update_form.html",
|
|
{"form": form},
|
|
)
|
|
return HttpResponse(
|
|
response.content.decode("utf-8") + "<script>location.reload();</script>"
|
|
)
|
|
return render(
|
|
request, "attendance/attendance_account/update_form.html", {"form": form}
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_AttendanceOverTime")
|
|
@require_http_methods(["POST"])
|
|
def attendance_overtime_delete(request, obj_id):
|
|
"""
|
|
This method is used to delete attendance overtime
|
|
args:
|
|
obj_id : attendance overtime id
|
|
"""
|
|
previous_data = request.GET.urlencode()
|
|
hx_target = request.META.get("HTTP_HX_TARGET", None)
|
|
try:
|
|
attendance = AttendanceOverTime.objects.get(id=obj_id)
|
|
attendance.delete()
|
|
if hx_target == "ot-table":
|
|
messages.success(request, _("Hour account deleted."))
|
|
except (AttendanceOverTime.DoesNotExist, OverflowError, ValueError):
|
|
if hx_target == "ot-table":
|
|
messages.error(request, _("Hour account not found"))
|
|
except ProtectedError:
|
|
if hx_target == "ot-table":
|
|
messages.error(request, _("You cannot delete this hour account"))
|
|
if hx_target and hx_target == "ot-table":
|
|
return redirect(f"/attendance/attendance-overtime-search?{previous_data}")
|
|
elif hx_target:
|
|
return HttpResponse()
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_attendanceovertime")
|
|
def attendance_account_bulk_delete(request):
|
|
"""
|
|
This method is used to bulk delete for Payslip
|
|
"""
|
|
ids = request.POST["ids"]
|
|
ids = json.loads(ids)
|
|
for id in ids:
|
|
try:
|
|
hour_account = AttendanceOverTime.objects.get(id=id)
|
|
hour_account.delete()
|
|
messages.success(
|
|
request,
|
|
_("{employee} hour account deleted.").format(
|
|
employee=hour_account.employee_id
|
|
),
|
|
)
|
|
except AttendanceOverTime.DoesNotExist:
|
|
messages.error(request, _("Hour account not found."))
|
|
except ProtectedError:
|
|
messages.error(
|
|
request,
|
|
_("You cannot delete {hour_account}").format(hour_account=hour_account),
|
|
)
|
|
return JsonResponse({"message": "Success"})
|
|
|
|
|
|
@login_required
|
|
def attendance_activity_view(request):
|
|
"""
|
|
This method will render a template to view all attendance activities
|
|
"""
|
|
previous_data = request.GET.urlencode()
|
|
filter_obj = AttendanceActivityFilter(request.GET)
|
|
attendance_activities = filter_obj.qs
|
|
self_attendance_activities = attendance_activities.filter(
|
|
employee_id__employee_user_id=request.user
|
|
)
|
|
attendance_activities = filtersubordinates(
|
|
request, filter_obj.qs, "attendance.view_attendanceovertime"
|
|
)
|
|
attendance_activities = attendance_activities | self_attendance_activities
|
|
attendance_activities = attendance_activities.distinct()
|
|
attendance_activities = attendance_activities.order_by("-pk")
|
|
activity_ids = json.dumps(
|
|
[instance.id for instance in paginator_qry(attendance_activities, None)]
|
|
)
|
|
export_form = AttendanceActivityExportForm()
|
|
if attendance_activities.exists():
|
|
template = "attendance/attendance_activity/attendance_activity_view.html"
|
|
else:
|
|
template = "attendance/attendance_activity/activity_empty.html"
|
|
return render(
|
|
request,
|
|
template,
|
|
{
|
|
"data": paginator_qry(attendance_activities, request.GET.get("page")),
|
|
"pd": previous_data,
|
|
"f": filter_obj,
|
|
"export": AttendanceActivityFilter(
|
|
queryset=AttendanceActivity.objects.all()
|
|
),
|
|
"gp_fields": AttendanceActivityReGroup.fields,
|
|
"export_form": export_form,
|
|
"activity_ids": activity_ids,
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
def activity_single_view(request, obj_id):
|
|
request_copy = request.GET.copy()
|
|
request_copy.pop("instances_ids", None)
|
|
previous_data = request_copy.urlencode()
|
|
activity = AttendanceActivity.objects.filter(id=obj_id).first()
|
|
|
|
instance_ids_json = request.GET["instances_ids"]
|
|
instance_ids = json.loads(instance_ids_json) if instance_ids_json else []
|
|
previous_instance, next_instance = closest_numbers(instance_ids, obj_id)
|
|
context = {
|
|
"pd": previous_data,
|
|
"activity": activity,
|
|
"previous_instance": previous_instance,
|
|
"next_instance": next_instance,
|
|
"instance_ids_json": instance_ids_json,
|
|
}
|
|
if activity:
|
|
attendance = Attendance.objects.filter(
|
|
attendance_date=activity.attendance_date
|
|
).first()
|
|
context["attendance"] = attendance
|
|
|
|
return render(
|
|
request,
|
|
"attendance/attendance_activity/single_attendance_activity.html",
|
|
context=context,
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_attendanceactivity")
|
|
@require_http_methods(["POST", "DELETE"])
|
|
def attendance_activity_delete(request, obj_id):
|
|
"""
|
|
This method is used to delete attendance activity
|
|
args:
|
|
obj_id : attendance activity id
|
|
"""
|
|
request_copy = request.GET.copy()
|
|
request_copy.pop("instances_ids", None)
|
|
previous_data = request_copy.urlencode()
|
|
try:
|
|
AttendanceActivity.objects.get(id=obj_id).delete()
|
|
messages.success(request, _("Attendance activity deleted"))
|
|
except AttendanceActivity.DoesNotExist:
|
|
messages.error(request, _("Attendance activity Does not exists.."))
|
|
except ProtectedError:
|
|
messages.error(request, _("You cannot delete this activity"))
|
|
if not request.GET.get("instances_ids"):
|
|
return redirect(f"/attendance/attendance-activity-search?{previous_data}")
|
|
else:
|
|
instances_ids = request.GET.get("instances_ids")
|
|
instances_list = json.loads(instances_ids)
|
|
if obj_id in instances_list:
|
|
instances_list.remove(obj_id)
|
|
previous_instance, next_instance = closest_numbers(
|
|
json.loads(instances_ids), obj_id
|
|
)
|
|
return redirect(
|
|
f"/attendance/attendance-activity-single-view/{next_instance}/?{previous_data}&instances_ids={instances_list}"
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_attendanceactivity")
|
|
@require_http_methods(["POST"])
|
|
def attendance_activity_bulk_delete(request):
|
|
"""
|
|
This method is used to delete bulk of attendances
|
|
"""
|
|
ids = request.POST["ids"]
|
|
ids = json.loads(ids)
|
|
for attendance_id in ids:
|
|
try:
|
|
activity = AttendanceActivity.objects.get(id=attendance_id)
|
|
activity.delete()
|
|
messages.success(
|
|
request,
|
|
_("{employee} activity deleted.").format(employee=activity.employee_id),
|
|
)
|
|
|
|
except (AttendanceActivity.DoesNotExist, OverflowError, ValueError):
|
|
messages.error(request, _("Attendance not found."))
|
|
return JsonResponse({"message": "Success"})
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.change_attendanceactivity")
|
|
def attendance_activity_export(request):
|
|
return export_data(
|
|
request=request,
|
|
model=AttendanceActivity,
|
|
filter_class=AttendanceActivityFilter,
|
|
form_class=AttendanceActivityExportForm,
|
|
file_name="Attendance_activity",
|
|
)
|
|
|
|
|
|
def employee_exists(request):
|
|
"""
|
|
This method return the employee instance and work info if not exists return None instead
|
|
"""
|
|
employee, employee_work_info = None, None
|
|
try:
|
|
employee = request.user.employee_get
|
|
employee_work_info = employee.employee_work_info
|
|
finally:
|
|
return (employee, employee_work_info)
|
|
|
|
|
|
def shift_schedule_today(day, shift):
|
|
"""
|
|
This function is used to find shift schedules for the day,
|
|
it will returns min hour,start time seconds end time seconds
|
|
args:
|
|
shift : shift instance
|
|
day : shift day object
|
|
"""
|
|
schedule_today = day.day_schedule.filter(shift_id=shift)
|
|
start_time_sec, end_time_sec, minimum_hour = 0, 0, "00:00"
|
|
if schedule_today.exists():
|
|
schedule_today = schedule_today[0]
|
|
minimum_hour = schedule_today.minimum_working_hour
|
|
start_time_sec = strtime_seconds(schedule_today.start_time.strftime("%H:%M"))
|
|
end_time_sec = strtime_seconds(schedule_today.end_time.strftime("%H:%M"))
|
|
return (minimum_hour, start_time_sec, end_time_sec)
|
|
|
|
|
|
def overtime_calculation(attendance):
|
|
"""
|
|
This method is used to calculate overtime of the attendance, it will
|
|
return difference between attendance worked hour and minimum hour if
|
|
and only worked hour greater than minimum hour, else return 00:00
|
|
args:
|
|
attendance : attendance instance
|
|
"""
|
|
|
|
minimum_hour = attendance.minimum_hour
|
|
at_work = attendance.attendance_worked_hour
|
|
at_work_sec = strtime_seconds(at_work)
|
|
minimum_hour_sec = strtime_seconds(minimum_hour)
|
|
if at_work_sec > minimum_hour_sec:
|
|
return format_time((at_work_sec - minimum_hour_sec))
|
|
return "00:00"
|
|
|
|
|
|
def activity_datetime(attendance_activity):
|
|
"""
|
|
This method is used to convert clock-in and clock-out of activity as datetime object
|
|
args:
|
|
attendance_activity : attendance activity instance
|
|
"""
|
|
|
|
# in
|
|
in_year = attendance_activity.clock_in_date.year
|
|
in_month = attendance_activity.clock_in_date.month
|
|
in_day = attendance_activity.clock_in_date.day
|
|
in_hour = attendance_activity.clock_in.hour
|
|
in_minute = attendance_activity.clock_in.minute
|
|
in_seconds = attendance_activity.clock_in.second
|
|
# out
|
|
out_year = attendance_activity.clock_out_date.year
|
|
out_month = attendance_activity.clock_out_date.month
|
|
out_day = attendance_activity.clock_out_date.day
|
|
out_hour = attendance_activity.clock_out.hour
|
|
out_minute = attendance_activity.clock_out.minute
|
|
out_seconds = attendance_activity.clock_out.second
|
|
return datetime(
|
|
in_year, in_month, in_day, in_hour, in_minute, in_seconds
|
|
), datetime(out_year, out_month, out_day, out_hour, out_minute, out_seconds)
|
|
|
|
|
|
@login_required
|
|
def on_time_view(request):
|
|
"""
|
|
This method render template to view all on come early out entries
|
|
"""
|
|
total_attendances = AttendanceFilters(request.GET).qs
|
|
ids_to_exclude = AttendanceLateComeEarlyOut.objects.filter(
|
|
attendance_id__id__in=[attendance.id for attendance in total_attendances],
|
|
type="late_come",
|
|
).values_list("attendance_id__id", flat=True)
|
|
# Exclude attendances with related objects in AttendanceLateComeEarlyOut
|
|
total_attendances = total_attendances.exclude(id__in=ids_to_exclude)
|
|
context = {
|
|
"attendances": total_attendances,
|
|
}
|
|
return render(
|
|
request, "attendance/attendance/attendance_on_time.html", context=context
|
|
)
|
|
|
|
|
|
@login_required
|
|
def late_come_early_out_view(request):
|
|
"""
|
|
This method render template to view all late come early out entries
|
|
"""
|
|
filter_obj = LateComeEarlyOutFilter(request.GET)
|
|
if filter_obj.qs.exists():
|
|
template = "attendance/late_come_early_out/reports.html"
|
|
else:
|
|
template = "attendance/late_come_early_out/reports_empty.html"
|
|
self_reports = filter_obj.qs.filter(employee_id__employee_user_id=request.user)
|
|
reports = filtersubordinates(
|
|
request, filter_obj.qs, "attendance.view_attendancelatecomeearlyout"
|
|
)
|
|
|
|
reports = reports | self_reports
|
|
reports = reports.distinct()
|
|
late_in_early_out_ids = json.dumps(
|
|
[instance.id for instance in paginator_qry(reports, None)]
|
|
)
|
|
previous_data = request.GET.urlencode()
|
|
export_form = LateComeEarlyOutExportForm()
|
|
data_dict = parse_qs(previous_data)
|
|
get_key_instances(AttendanceLateComeEarlyOut, data_dict)
|
|
return render(
|
|
request,
|
|
template,
|
|
{
|
|
"data": paginator_qry(reports, request.GET.get("page")),
|
|
"f": filter_obj,
|
|
"gp_fields": LateComeEarlyOutReGroup.fields,
|
|
"export": LateComeEarlyOutFilter(
|
|
queryset=AttendanceLateComeEarlyOut.objects.all()
|
|
),
|
|
"filter_dict": data_dict,
|
|
"export_form": export_form,
|
|
"late_in_early_out_ids": late_in_early_out_ids,
|
|
},
|
|
)
|
|
|
|
|
|
def late_in_early_out_single_view(request, obj_id):
|
|
request_copy = request.GET.copy()
|
|
request_copy.pop("instances_ids", None)
|
|
previous_data = request_copy.urlencode()
|
|
late_in_early_out = AttendanceLateComeEarlyOut.objects.filter(id=obj_id).first()
|
|
instance_ids_json = request.GET["instances_ids"]
|
|
instance_ids = json.loads(instance_ids_json) if instance_ids_json else []
|
|
previous_instance, next_instance = closest_numbers(instance_ids, obj_id)
|
|
context = {
|
|
"late_in_early_out": late_in_early_out,
|
|
"previous_instance": previous_instance,
|
|
"next_instance": next_instance,
|
|
"instance_ids_json": instance_ids_json,
|
|
"pd": previous_data,
|
|
}
|
|
return render(
|
|
request, "attendance/late_come_early_out/single_report.html", context=context
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_attendancelatecomeearlyout")
|
|
@require_http_methods(["POST"])
|
|
def late_come_early_out_delete(request, obj_id):
|
|
"""
|
|
This method is used to delete the late come early out instance
|
|
args:
|
|
obj_id : late come early out instance id
|
|
"""
|
|
request_copy = request.GET.copy()
|
|
request_copy.pop("instances_ids", None)
|
|
previous_data = request_copy.urlencode()
|
|
try:
|
|
AttendanceLateComeEarlyOut.objects.get(id=obj_id).delete()
|
|
messages.success(request, _("Late-in early-out deleted"))
|
|
except AttendanceLateComeEarlyOut.DoesNotExist:
|
|
messages.error(request, _("Late-in early-out does not exists.."))
|
|
except ProtectedError:
|
|
messages.error(request, _("You cannot delete this Late-in early-out"))
|
|
if not request.GET.get("instances_ids"):
|
|
return redirect(f"/attendance/late-come-early-out-search?{previous_data}")
|
|
else:
|
|
instances_ids = request.GET.get("instances_ids")
|
|
instances_list = json.loads(instances_ids)
|
|
if obj_id in instances_list:
|
|
instances_list.remove(obj_id)
|
|
previous_instance, next_instance = closest_numbers(
|
|
json.loads(instances_ids), obj_id
|
|
)
|
|
return redirect(
|
|
f"/attendance/late-in-early-out-single-view/{next_instance}/?{previous_data}&instances_ids={instances_list}"
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_attendancelatecomeearlyout")
|
|
@require_http_methods(["POST"])
|
|
def late_come_early_out_bulk_delete(request):
|
|
"""
|
|
This method is used to delete bulk of attendances
|
|
"""
|
|
ids = request.POST["ids"]
|
|
ids = json.loads(ids)
|
|
for attendance_id in ids:
|
|
try:
|
|
late_come = AttendanceLateComeEarlyOut.objects.get(id=attendance_id)
|
|
late_come.delete()
|
|
messages.success(
|
|
request,
|
|
_("{employee} Late-in early-out deleted.").format(
|
|
employee=late_come.employee_id
|
|
),
|
|
)
|
|
except (AttendanceLateComeEarlyOut.DoesNotExist, OverflowError, ValueError):
|
|
messages.error(request, _("Attendance not found."))
|
|
return JsonResponse({"message": "Success"})
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.change_attendancelatecomeearlyout")
|
|
def late_come_early_out_export(request):
|
|
"""
|
|
Export late come early out data to an Excel file.
|
|
This view function takes a GET request and exports attendance late come early out data into an Excel file.
|
|
The exported Excel file will include the selected fields from the AttendanceLateComeEarlyOut model.
|
|
"""
|
|
return export_data(
|
|
request=request,
|
|
model=AttendanceLateComeEarlyOut,
|
|
filter_class=LateComeEarlyOutFilter,
|
|
form_class=LateComeEarlyOutExportForm,
|
|
file_name="Late_come_",
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.add_attendancevalidationcondition")
|
|
def validation_condition_create(request):
|
|
"""
|
|
This method render a form to create attendance validation conditions,
|
|
and create if the form is valid.
|
|
"""
|
|
form = AttendanceValidationConditionForm()
|
|
condition = AttendanceValidationCondition.objects.first()
|
|
if request.method == "POST":
|
|
form = AttendanceValidationConditionForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
return render(
|
|
request,
|
|
"attendance/break_point/condition.html",
|
|
{"form": form, "condition": condition},
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.change_attendancevalidationcondition")
|
|
def validation_condition_update(request, obj_id):
|
|
"""
|
|
This method is used to update validation condition
|
|
Args:
|
|
obj_id : validation condition instance id
|
|
"""
|
|
condition = AttendanceValidationCondition.objects.get(id=obj_id)
|
|
form = AttendanceValidationConditionForm(instance=condition)
|
|
if request.method == "POST":
|
|
form = AttendanceValidationConditionForm(request.POST, instance=condition)
|
|
if form.is_valid():
|
|
form.save()
|
|
return render(
|
|
request,
|
|
"attendance/break_point/condition.html",
|
|
{"form": form, "condition": condition},
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.change_attendancevalidationcondition")
|
|
@require_http_methods(["POST"])
|
|
def validation_condition_delete(request, obj_id):
|
|
"""
|
|
This method is used to delete created validation condition
|
|
args:
|
|
obj_id : validation condition id
|
|
"""
|
|
try:
|
|
AttendanceValidationCondition.objects.get(id=obj_id).delete()
|
|
messages.success(request, _("validation condition deleted."))
|
|
except AttendanceValidationCondition.DoesNotExist:
|
|
messages.error(request, _("validation condition Does not exists.."))
|
|
except ProtectedError:
|
|
messages.error(request, _("You cannot delete this validation condition."))
|
|
return redirect("/attendance/validation-condition-view")
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(["POST"])
|
|
@manager_can_enter("attendance.change_attendance")
|
|
def validate_bulk_attendance(request):
|
|
"""
|
|
This method is used to validate bulk of attendances
|
|
"""
|
|
ids = request.POST["ids"]
|
|
ids = json.loads(ids)
|
|
for obj_id in ids:
|
|
try:
|
|
attendance = Attendance.objects.get(id=obj_id)
|
|
attendance.attendance_validated = True
|
|
attendance.save()
|
|
messages.success(request, _("Attendance validated."))
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Your attendance for the date {attendance.attendance_date} is validated",
|
|
verb_ar=f"تم التحقق من حضورك في تاريخ {attendance.attendance_date}",
|
|
verb_de=f"Ihre Anwesenheit für das Datum {attendance.attendance_date} wurde bestätigt",
|
|
verb_es=f"Se ha validado su asistencia para la fecha {attendance.attendance_date}",
|
|
verb_fr=f"Votre présence pour la date {attendance.attendance_date} est validée",
|
|
redirect=f"/attendance/view-my-attendance?id={attendance.id}",
|
|
icon="checkmark",
|
|
)
|
|
except (Attendance.DoesNotExist, OverflowError, ValueError):
|
|
messages.error(request, _("Attendance not found"))
|
|
return JsonResponse({"message": "success"})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.change_attendance")
|
|
def validate_this_attendance(request, obj_id):
|
|
"""
|
|
This method is used to validate attendance
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
try:
|
|
attendance = Attendance.objects.get(id=obj_id)
|
|
attendance.attendance_validated = True
|
|
attendance.save()
|
|
urlencode = request.GET.urlencode()
|
|
modified_url = f"/attendance/attendance-view/?{urlencode}"
|
|
messages.success(
|
|
request,
|
|
(
|
|
f"{attendance.employee_id} {attendance.attendance_date.strftime('%d %b %Y') }"
|
|
+ _("Attendance validated.")
|
|
),
|
|
)
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Your attendance for the date {attendance.attendance_date} is validated",
|
|
verb_ar=f"تم تحقيق حضورك في تاريخ {attendance.attendance_date}",
|
|
verb_de=f"Deine Anwesenheit für das Datum {attendance.attendance_date} ist bestätigt.",
|
|
verb_es=f"Se valida tu asistencia para la fecha {attendance.attendance_date}.",
|
|
verb_fr=f"Votre présence pour la date {attendance.attendance_date} est validée.",
|
|
redirect=f"/attendance/view-my-attendance?id={attendance.id}",
|
|
icon="checkmark",
|
|
)
|
|
except (Attendance.DoesNotExist, ValueError):
|
|
messages.error(request, _("Attendance not found"))
|
|
|
|
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
|
|
|
|
|
@login_required
|
|
def revalidate_this_attendance(request, obj_id):
|
|
"""
|
|
This method is used to not validate the attendance.
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
|
|
attendance = Attendance.objects.get(id=obj_id)
|
|
if is_reportingmanger(request, attendance) or request.user.has_perm(
|
|
"attendance.change_attendance"
|
|
):
|
|
attendance.attendance_validated = False
|
|
attendance.save()
|
|
with contextlib.suppress(Exception):
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=(
|
|
attendance.employee_id.employee_work_info.reporting_manager_id.employee_user_id
|
|
),
|
|
verb=f"{attendance.employee_id} requested revalidation for \
|
|
{attendance.attendance_date} attendance",
|
|
verb_ar=f"{attendance.employee_id} طلب إعادة\
|
|
التحقق من حضور تاريخ {attendance.attendance_date}",
|
|
verb_de=f"{attendance.employee_id} beantragte eine Neubewertung der \
|
|
Teilnahme am {attendance.attendance_date}",
|
|
verb_es=f"{attendance.employee_id} solicitó la validación nuevamente \
|
|
para la asistencia del {attendance.attendance_date}",
|
|
verb_fr=f"{attendance.employee_id} a demandé une revalidation pour la \
|
|
présence du {attendance.attendance_date}",
|
|
redirect=f"/attendance/view-my-attendance?id={attendance.id}",
|
|
icon="refresh",
|
|
)
|
|
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
|
return HttpResponse("You Cannot Request for others attendance")
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.change_attendance")
|
|
def approve_overtime(request, obj_id):
|
|
"""
|
|
This method is used to approve attendance overtime
|
|
args:
|
|
obj_id : attendance id
|
|
"""
|
|
try:
|
|
attendance = Attendance.objects.get(id=obj_id)
|
|
attendance.attendance_overtime_approve = True
|
|
attendance.save()
|
|
urlencode = request.GET.urlencode()
|
|
modified_url = f"/attendance/attendance-view/?{urlencode}"
|
|
messages.success(
|
|
request,
|
|
f"{attendance.employee_id}'s {attendance.attendance_date.strftime('%d %b %Y')} overtime approved",
|
|
)
|
|
with contextlib.suppress(Exception):
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Your {attendance.attendance_date}'s attendance \
|
|
overtime approved.",
|
|
verb_ar=f"تمت الموافقة على إضافة ساعات العمل الإضافية لتاريخ \
|
|
{attendance.attendance_date}.",
|
|
verb_de=f"Die Überstunden für den {attendance.attendance_date}\
|
|
wurden genehmigt.",
|
|
verb_es=f"Se ha aprobado el tiempo extra de asistencia para el \
|
|
{attendance.attendance_date}.",
|
|
verb_fr=f"Les heures supplémentaires pour la date\
|
|
{attendance.attendance_date} ont été approuvées.",
|
|
redirect=f"/attendance/attendance-overtime-view?id={attendance.id}",
|
|
icon="checkmark",
|
|
)
|
|
except (Attendance.DoesNotExist, OverflowError):
|
|
messages.error(request, _("Attendance not found"))
|
|
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter("attendance.change_attendance")
|
|
def approve_bulk_overtime(request):
|
|
"""
|
|
This method is used to approve bulk of attendance
|
|
"""
|
|
ids = request.POST["ids"]
|
|
ids = json.loads(ids)
|
|
for attendance_id in ids:
|
|
try:
|
|
attendance = Attendance.objects.get(id=attendance_id)
|
|
attendance.attendance_overtime_approve = True
|
|
attendance.save()
|
|
messages.success(request, _("Overtime approved"))
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Overtime approved for\
|
|
{attendance.attendance_date}'s attendance",
|
|
verb_ar=f"تمت الموافقة على العمل الإضافي لحضور تاريخ \
|
|
{attendance.attendance_date}",
|
|
verb_de=f"Überstunden für die Anwesenheit am \
|
|
{attendance.attendance_date} genehmigt",
|
|
verb_es=f"Horas extra aprobadas para la asistencia del \
|
|
{attendance.attendance_date}",
|
|
verb_fr=f"Heures supplémentaires approuvées pour la présence du \
|
|
{attendance.attendance_date}",
|
|
redirect=f"/attendance/attendance-overtime-view?id={attendance.id}",
|
|
icon="checkmark",
|
|
)
|
|
except (Attendance.DoesNotExist, OverflowError, ValueError):
|
|
messages.error(request, _("Attendance not found"))
|
|
return JsonResponse({"message": "Success"})
|
|
|
|
|
|
def form_shift_dynamic_data(request):
|
|
"""
|
|
This method is used to update the shift details to the form
|
|
"""
|
|
shift_id = request.POST["shift_id"]
|
|
attendance_date_str = request.POST.get("attendance_date")
|
|
today = datetime.now()
|
|
attendance_date = date(day=today.day, month=today.month, year=today.year)
|
|
if attendance_date_str is not None and attendance_date_str != "":
|
|
attendance_date = datetime.strptime(attendance_date_str, "%Y-%m-%d").date()
|
|
day = attendance_date.strftime("%A").lower()
|
|
schedule_today = EmployeeShiftSchedule.objects.filter(
|
|
shift_id__id=shift_id, day__day=day
|
|
).first()
|
|
shift_start_time = ""
|
|
shift_end_time = ""
|
|
minimum_hour = "00:00"
|
|
attendance_clock_out_date = attendance_date
|
|
if schedule_today is not None:
|
|
shift_start_time = schedule_today.start_time
|
|
shift_end_time = schedule_today.end_time
|
|
minimum_hour = schedule_today.minimum_working_hour
|
|
if shift_end_time < shift_start_time:
|
|
attendance_clock_out_date = attendance_date + timedelta(days=1)
|
|
worked_hour = minimum_hour
|
|
if attendance_date == date(day=today.day, month=today.month, year=today.year):
|
|
shift_end_time = datetime.now().strftime("%H:%M")
|
|
worked_hour = "00:00"
|
|
|
|
minimum_hour = attendance_day_checking(str(attendance_date), minimum_hour)
|
|
|
|
return JsonResponse(
|
|
{
|
|
"shift_start_time": shift_start_time,
|
|
"shift_end_time": shift_end_time,
|
|
"checkin_date": attendance_date.strftime("%Y-%m-%d"),
|
|
"minimum_hour": minimum_hour,
|
|
"worked_hour": worked_hour,
|
|
"checkout_date": attendance_clock_out_date.strftime("%Y-%m-%d"),
|
|
}
|
|
)
|
|
|
|
|
|
@login_required
|
|
def form_date_checking(request):
|
|
attendance_date_str = request.POST["attendance_date"]
|
|
minimum_hour = "00:00"
|
|
# Converting to date type.
|
|
attendance_date = datetime.strptime(attendance_date_str, "%Y-%m-%d").date()
|
|
|
|
if request.POST["shift_id"]:
|
|
shift_id = request.POST["shift_id"]
|
|
day = attendance_date.strftime("%A").lower()
|
|
schedule_today = EmployeeShiftSchedule.objects.filter(
|
|
shift_id__id=shift_id, day__day=day
|
|
).first()
|
|
|
|
# Checking the Shift is present in the selected attendance day.
|
|
if schedule_today is not None:
|
|
minimum_hour = schedule_today.minimum_working_hour
|
|
|
|
attendance_date = str(attendance_date)
|
|
minimum_hour = attendance_day_checking(attendance_date, minimum_hour)
|
|
|
|
return JsonResponse(
|
|
{
|
|
"minimum_hour": minimum_hour,
|
|
}
|
|
)
|
|
|
|
|
|
@login_required
|
|
def user_request_one_view(request, id):
|
|
"""
|
|
function used to view one user attendance request.
|
|
|
|
Parameters:
|
|
request (HttpRequest): The HTTP request object.
|
|
|
|
Returns:
|
|
GET : return one user attendance request view template
|
|
"""
|
|
attendance_request = Attendance.objects.get(id=id)
|
|
|
|
at_work_seconds = attendance_request.at_work_second
|
|
hours_at_work = at_work_seconds // 3600
|
|
minutes_at_work = (at_work_seconds % 3600) // 60
|
|
at_work = "{:02}:{:02}".format(hours_at_work, minutes_at_work)
|
|
|
|
over_time_seconds = attendance_request.overtime_second
|
|
hours_over_time = over_time_seconds // 3600
|
|
minutes_over_time = (over_time_seconds % 3600) // 60
|
|
over_time = "{:02}:{:02}".format(hours_over_time, minutes_over_time)
|
|
instance_ids_json = request.GET["instances_ids"]
|
|
instance_ids = json.loads(instance_ids_json) if instance_ids_json else []
|
|
previous_instance, next_instance = closest_numbers(instance_ids, id)
|
|
return render(
|
|
request,
|
|
"attendance/attendance/attendance_request_one.html",
|
|
{
|
|
"attendance_request": attendance_request,
|
|
"at_work": at_work,
|
|
"over_time": over_time,
|
|
"previous_instance": previous_instance,
|
|
"next_instance": next_instance,
|
|
"instance_ids_json": instance_ids_json,
|
|
"dashboard": request.GET.get("dashboard"),
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
def hour_attendance_select(request):
|
|
page_number = request.GET.get("page")
|
|
context = {}
|
|
|
|
if page_number == "all":
|
|
if request.user.has_perm("attendance.view_attendanceovertime"):
|
|
employees = AttendanceOverTime.objects.all()
|
|
else:
|
|
employees = AttendanceOverTime.objects.filter(
|
|
employee_id__employee_user_id=request.user
|
|
) | AttendanceOverTime.objects.filter(
|
|
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
|
|
)
|
|
|
|
employee_ids = [str(emp.id) for emp in employees]
|
|
total_count = employees.count()
|
|
|
|
context = {"employee_ids": employee_ids, "total_count": total_count}
|
|
|
|
return JsonResponse(context, safe=False)
|
|
|
|
|
|
@login_required
|
|
def hour_attendance_select_filter(request):
|
|
page_number = request.GET.get("page")
|
|
filtered = request.GET.get("filter")
|
|
filters = json.loads(filtered) if filtered else {}
|
|
|
|
if page_number == "all":
|
|
if request.user.has_perm("attendance.view_attendanceovertime"):
|
|
employee_filter = AttendanceOverTimeFilter(
|
|
filters, queryset=AttendanceOverTime.objects.all()
|
|
)
|
|
else:
|
|
employee_filter = AttendanceOverTimeFilter(
|
|
filters,
|
|
queryset=AttendanceOverTime.objects.filter(
|
|
employee_id__employee_user_id=request.user
|
|
)
|
|
| AttendanceOverTime.objects.filter(
|
|
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
|
|
),
|
|
)
|
|
|
|
# Get the filtered queryset
|
|
filtered_employees = employee_filter.qs
|
|
|
|
employee_ids = [str(emp.id) for emp in filtered_employees]
|
|
total_count = filtered_employees.count()
|
|
|
|
context = {"employee_ids": employee_ids, "total_count": total_count}
|
|
|
|
return JsonResponse(context)
|
|
|
|
|
|
@login_required
|
|
def activity_attendance_select(request):
|
|
page_number = request.GET.get("page")
|
|
|
|
if page_number == "all":
|
|
if request.user.has_perm("attendance.view_attendanceovertime"):
|
|
employees = AttendanceActivity.objects.all()
|
|
else:
|
|
employees = AttendanceActivity.objects.filter(
|
|
employee_id__employee_user_id=request.user
|
|
) | AttendanceActivity.objects.filter(
|
|
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
|
|
)
|
|
|
|
employee_ids = [str(emp.id) for emp in employees]
|
|
total_count = employees.count()
|
|
|
|
context = {"employee_ids": employee_ids, "total_count": total_count}
|
|
|
|
return JsonResponse(context, safe=False)
|
|
|
|
|
|
@login_required
|
|
def activity_attendance_select_filter(request):
|
|
page_number = request.GET.get("page")
|
|
filtered = request.GET.get("filter")
|
|
filters = json.loads(filtered) if filtered else {}
|
|
|
|
if page_number == "all":
|
|
if request.user.has_perm("attendance.view_attendanceovertime"):
|
|
employee_filter = AttendanceActivityFilter(
|
|
filters, queryset=AttendanceActivity.objects.all()
|
|
)
|
|
else:
|
|
employee_filter = AttendanceActivityFilter(
|
|
filters,
|
|
queryset=AttendanceActivity.objects.filter(
|
|
employee_id__employee_user_id=request.user
|
|
)
|
|
| AttendanceActivity.objects.filter(
|
|
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
|
|
),
|
|
)
|
|
|
|
# Get the filtered queryset
|
|
filtered_employees = employee_filter.qs
|
|
|
|
employee_ids = [str(emp.id) for emp in filtered_employees]
|
|
total_count = filtered_employees.count()
|
|
|
|
context = {"employee_ids": employee_ids, "total_count": total_count}
|
|
|
|
return JsonResponse(context)
|
|
|
|
|
|
@login_required
|
|
def latecome_attendance_select(request):
|
|
page_number = request.GET.get("page")
|
|
|
|
if page_number == "all":
|
|
if request.user.has_perm("attendance.view_attendancelatecomeearlyout"):
|
|
employees = AttendanceLateComeEarlyOut.objects.all()
|
|
else:
|
|
employees = AttendanceLateComeEarlyOut.objects.filter(
|
|
employee_id__employee_user_id=request.user
|
|
) | AttendanceLateComeEarlyOut.objects.filter(
|
|
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
|
|
)
|
|
|
|
employee_ids = [str(emp.id) for emp in employees]
|
|
total_count = employees.count()
|
|
|
|
context = {"employee_ids": employee_ids, "total_count": total_count}
|
|
|
|
return JsonResponse(context, safe=False)
|
|
|
|
|
|
@login_required
|
|
def latecome_attendance_select_filter(request):
|
|
page_number = request.GET.get("page")
|
|
filtered = request.GET.get("filter")
|
|
filters = json.loads(filtered) if filtered else {}
|
|
|
|
if page_number == "all":
|
|
if request.user.has_perm("attendance.view_attendancelatecomeearlyout"):
|
|
employee_filter = LateComeEarlyOutFilter(
|
|
filters, queryset=AttendanceLateComeEarlyOut.objects.all()
|
|
)
|
|
else:
|
|
employee_filter = LateComeEarlyOutFilter(
|
|
filters,
|
|
queryset=AttendanceLateComeEarlyOut.objects.filter(
|
|
employee_id__employee_user_id=request.user
|
|
)
|
|
| AttendanceLateComeEarlyOut.objects.filter(
|
|
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
|
|
),
|
|
)
|
|
|
|
# Get the filtered queryset
|
|
filtered_employees = employee_filter.qs
|
|
|
|
employee_ids = [str(emp.id) for emp in filtered_employees]
|
|
total_count = filtered_employees.count()
|
|
|
|
context = {"employee_ids": employee_ids, "total_count": total_count}
|
|
|
|
return JsonResponse(context)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.add_gracetime")
|
|
def create_grace_time(request):
|
|
"""
|
|
function used to create grace time .
|
|
|
|
Parameters:
|
|
request (HttpRequest): The HTTP request object.
|
|
|
|
Returns:
|
|
GET : return grace time form template
|
|
"""
|
|
is_default = eval(request.GET.get("default"))
|
|
form = GraceTimeForm(initial={"is_default": is_default})
|
|
|
|
if request.method == "POST":
|
|
form = GraceTimeForm(request.POST)
|
|
if form.is_valid():
|
|
instance = form.save(commit=False)
|
|
instance.save()
|
|
messages.success(request, _("Grace time created successfully."))
|
|
return HttpResponse("<script>window.location.reload()</script>")
|
|
return render(
|
|
request,
|
|
"attendance/grace_time/grace_time_form.html",
|
|
{"form": form, "is_default": is_default},
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.change_gracetime")
|
|
def update_grace_time(request, grace_id):
|
|
"""
|
|
function used to create grace time .
|
|
|
|
Parameters:
|
|
request (HttpRequest): The HTTP request object.
|
|
grace_id: id of grace time object
|
|
Returns:
|
|
GET : return grace time form template
|
|
"""
|
|
grace_time = GraceTime.objects.get(id=grace_id)
|
|
form = GraceTimeForm(instance=grace_time)
|
|
if request.method == "POST":
|
|
form = GraceTimeForm(request.POST, instance=grace_time)
|
|
if form.is_valid():
|
|
instance = form.save(commit=False)
|
|
instance.save()
|
|
messages.success(request, _("Grace time updated successfully."))
|
|
return HttpResponse("<script>window.location.reload()</script>")
|
|
context = {
|
|
"form": form,
|
|
"grace_id": grace_id,
|
|
}
|
|
return render(
|
|
request, "attendance/grace_time/grace_time_form.html", context=context
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.delete_gracetime")
|
|
def delete_grace_time(request, grace_id):
|
|
"""
|
|
function used to delete grace time .
|
|
|
|
Parameters:
|
|
request (HttpRequest): The HTTP request object.
|
|
grace_id: id of grace time object
|
|
Returns:
|
|
GET : return grace time form template
|
|
"""
|
|
try:
|
|
GraceTime.objects.get(id=grace_id).delete()
|
|
messages.success(request, _("Grace time deleted successfully."))
|
|
except GraceTime.DoesNotExist:
|
|
messages.error(request, _("Grace Time Does not exists.."))
|
|
except ProtectedError:
|
|
messages.error(request, _("Related datas exists."))
|
|
if request.GET.get("view") == "shift":
|
|
return redirect("/settings/grace-settings-view")
|
|
else:
|
|
return redirect("/settings/grace-settings-view")
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.update_gracetime")
|
|
def update_isactive_gracetime(request):
|
|
"""
|
|
ajax function to update is active field in grace time.
|
|
Args:
|
|
- isChecked: Boolean value representing the state of grace time,
|
|
- graceId: Id of grace time object
|
|
"""
|
|
isChecked = request.POST.get("isChecked")
|
|
graceId = request.POST.get("graceId")
|
|
grace_time = GraceTime.objects.get(id=graceId)
|
|
if isChecked == "true":
|
|
grace_time.is_active = True
|
|
|
|
response = {
|
|
"type": "success",
|
|
"message": _("Default grace time activated successfully."),
|
|
}
|
|
else:
|
|
grace_time.is_active = False
|
|
response = {
|
|
"type": "success",
|
|
"message": _("Default grace time deactivated successfully."),
|
|
}
|
|
grace_time.save()
|
|
return JsonResponse(response)
|
|
|
|
|
|
@login_required
|
|
def create_attendancerequest_comment(request, attendance_id):
|
|
"""
|
|
This method renders form and template to create Attendance request comments
|
|
"""
|
|
previous_data = request.GET.urlencode()
|
|
attendance = Attendance.objects.filter(id=attendance_id).first()
|
|
emp = request.user.employee_get
|
|
form = AttendancerequestCommentForm(
|
|
initial={"employee_id": emp.id, "request_id": attendance_id}
|
|
)
|
|
|
|
if request.method == "POST":
|
|
form = AttendancerequestCommentForm(request.POST)
|
|
if form.is_valid():
|
|
form.instance.employee_id = emp
|
|
form.instance.request_id = attendance
|
|
form.save()
|
|
comments = AttendancerequestComment.objects.filter(
|
|
request_id=attendance_id
|
|
).order_by("-created_at")
|
|
no_comments = False
|
|
if not comments.exists():
|
|
no_comments = True
|
|
form = AttendancerequestCommentForm(
|
|
initial={"employee_id": emp.id, "request_id": attendance_id}
|
|
)
|
|
messages.success(request, _("Comment added successfully!"))
|
|
if (
|
|
attendance.employee_id.employee_work_info.reporting_manager_id
|
|
is not None
|
|
):
|
|
if request.user.employee_get.id == attendance.employee_id.id:
|
|
rec = (
|
|
attendance.employee_id.employee_work_info.reporting_manager_id.employee_user_id
|
|
)
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=rec,
|
|
verb=f"{attendance.employee_id}'s attendance request has received a comment.",
|
|
verb_ar=f"تلقت طلب الحضور {attendance.employee_id} تعليقًا.",
|
|
verb_de=f"{attendance.employee_id}s Anfrage zur Anwesenheit hat einen Kommentar erhalten.",
|
|
verb_es=f"La solicitud de asistencia de {attendance.employee_id} ha recibido un comentario.",
|
|
verb_fr=f"La demande de présence de {attendance.employee_id} a reçu un commentaire.",
|
|
redirect=f"/attendance/request-attendance-view?id={attendance.id}",
|
|
icon="chatbox-ellipses",
|
|
)
|
|
elif (
|
|
request.user.employee_get.id
|
|
== attendance.employee_id.employee_work_info.reporting_manager_id.id
|
|
):
|
|
rec = attendance.employee_id.employee_user_id
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=rec,
|
|
verb="Your attendance request has received a comment.",
|
|
verb_ar="تلقى طلب الحضور الخاص بك تعليقًا.",
|
|
verb_de="Ihr Antrag auf Anwesenheit hat einen Kommentar erhalten.",
|
|
verb_es="Tu solicitud de asistencia ha recibido un comentario.",
|
|
verb_fr="Votre demande de présence a reçu un commentaire.",
|
|
redirect=f"/attendance/request-attendance-view?id={attendance.id}",
|
|
icon="chatbox-ellipses",
|
|
)
|
|
else:
|
|
rec = [
|
|
attendance.employee_id.employee_user_id,
|
|
attendance.employee_id.employee_work_info.reporting_manager_id.employee_user_id,
|
|
]
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=rec,
|
|
verb=f"{attendance.employee_id}'s attendance request has received a comment.",
|
|
verb_ar=f"تلقت طلب الحضور {attendance.employee_id} تعليقًا.",
|
|
verb_de=f"{attendance.employee_id}s Anfrage zur Anwesenheit hat einen Kommentar erhalten.",
|
|
verb_es=f"La solicitud de asistencia de {attendance.employee_id} ha recibido un comentario.",
|
|
verb_fr=f"La demande de présence de {attendance.employee_id} a reçu un commentaire.",
|
|
redirect=f"/attendance/request-attendance-view?id={attendance.id}",
|
|
icon="chatbox-ellipses",
|
|
)
|
|
else:
|
|
rec = attendance.employee_id.employee_user_id
|
|
notify.send(
|
|
request.user.employee_get,
|
|
recipient=rec,
|
|
verb="Your attendance request has received a comment.",
|
|
verb_ar="تلقى طلب الحضور الخاص بك تعليقًا.",
|
|
verb_de="Ihr Antrag auf Anwesenheit hat einen Kommentar erhalten.",
|
|
verb_es="Tu solicitud de asistencia ha recibido un comentario.",
|
|
verb_fr="Votre demande de présence a reçu un commentaire.",
|
|
redirect=f"/attendance/request-attendance-view?id={attendance.id}",
|
|
icon="chatbox-ellipses",
|
|
)
|
|
return render(
|
|
request,
|
|
"requests/attendance/attendance_comment.html",
|
|
{
|
|
"comments": comments,
|
|
"no_comments": no_comments,
|
|
"request_id": attendance_id,
|
|
},
|
|
)
|
|
return render(
|
|
request,
|
|
"requests/attendance/attendance_comment.html",
|
|
{
|
|
"form": form,
|
|
"request_id": attendance_id,
|
|
"pd": previous_data,
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
def view_attendancerequest_comment(request, attendance_id):
|
|
"""
|
|
This method is used to show Attendance request comments
|
|
"""
|
|
comments = AttendancerequestComment.objects.filter(
|
|
request_id=attendance_id
|
|
).order_by("-created_at")
|
|
no_comments = False
|
|
if not comments.exists():
|
|
no_comments = True
|
|
|
|
if request.FILES:
|
|
files = request.FILES.getlist("files")
|
|
comment_id = request.GET["comment_id"]
|
|
comment = AttendancerequestComment.objects.get(id=comment_id)
|
|
attachments = []
|
|
for file in files:
|
|
file_instance = AttendancerequestFile()
|
|
file_instance.file = file
|
|
file_instance.save()
|
|
attachments.append(file_instance)
|
|
comment.files.add(*attachments)
|
|
|
|
return render(
|
|
request,
|
|
"requests/attendance/attendance_comment.html",
|
|
{"comments": comments, "no_comments": no_comments, "request_id": attendance_id},
|
|
)
|
|
|
|
|
|
@login_required
|
|
def delete_attendancerequest_comment(request, comment_id):
|
|
"""
|
|
This method is used to delete Attendance request comments
|
|
"""
|
|
|
|
comment = AttendancerequestComment.objects.get(id=comment_id)
|
|
attendance_id = comment.request_id.id
|
|
comment.delete()
|
|
messages.success(request, _("Comment deleted successfully!"))
|
|
return redirect("attendance-request-view-comment", attendance_id=attendance_id)
|
|
|
|
|
|
@login_required
|
|
def delete_comment_file(request):
|
|
"""
|
|
Used to delete attachment
|
|
"""
|
|
ids = request.GET.getlist("ids")
|
|
AttendancerequestFile.objects.filter(id__in=ids).delete()
|
|
leave_id = request.GET["leave_id"]
|
|
comments = AttendancerequestComment.objects.filter(request_id=leave_id).order_by(
|
|
"-created_at"
|
|
)
|
|
return render(
|
|
request,
|
|
"requests/attendance/attendance_comment.html",
|
|
{
|
|
"comments": comments,
|
|
"request_id": leave_id,
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
def work_records(request):
|
|
employees = Employee.objects.filter(is_active=True)
|
|
data = []
|
|
today = date.today()
|
|
month_matrix = calendar.monthcalendar(today.year, today.month)
|
|
|
|
days = [day for week in month_matrix for day in week if day != 0]
|
|
current_month_date_list = [
|
|
datetime(today.year, today.month, day).date() for day in days
|
|
]
|
|
|
|
for employee in employees:
|
|
work_record_list = []
|
|
work_records_dict = {
|
|
record.date: record
|
|
for record in WorkRecord.objects.filter(
|
|
employee_id=employee, date__in=current_month_date_list
|
|
)
|
|
}
|
|
|
|
for day in current_month_date_list:
|
|
work_record = work_records_dict.get(day, None)
|
|
work_record_list.append(work_record)
|
|
data.append(
|
|
{
|
|
"employee": employee,
|
|
"work_record": work_record_list,
|
|
}
|
|
)
|
|
|
|
context = {
|
|
"current_date": today,
|
|
"current_month_dates_list": current_month_date_list,
|
|
"data": paginator_qry(data, 1),
|
|
}
|
|
return render(
|
|
request, "attendance/work_record/work_record_view.html", context=context
|
|
)
|
|
|
|
|
|
@login_required
|
|
@hx_request_required
|
|
def work_records_change_month(request):
|
|
if request.GET.get("month"):
|
|
date_obj = request.GET.get("month")
|
|
month = int(date_obj.split("-")[1])
|
|
year = int(date_obj.split("-")[0])
|
|
else:
|
|
month = date.today().month
|
|
year = date.today().year
|
|
|
|
employees = Employee.objects.filter(is_active=True)
|
|
data = []
|
|
month_matrix = calendar.monthcalendar(year, month)
|
|
|
|
days = [day for week in month_matrix for day in week if day != 0]
|
|
current_month_date_list = [datetime(year, month, day).date() for day in days]
|
|
|
|
for employee in employees:
|
|
work_record_list = []
|
|
work_records_dict = {
|
|
record.date: record
|
|
for record in WorkRecord.objects.filter(
|
|
employee_id=employee, date__in=current_month_date_list
|
|
)
|
|
}
|
|
|
|
for day in current_month_date_list:
|
|
work_record = work_records_dict.get(day, None)
|
|
work_record_list.append(work_record)
|
|
data.append(
|
|
{
|
|
"employee": employee,
|
|
"work_record": work_record_list,
|
|
}
|
|
)
|
|
|
|
context = {
|
|
"current_month_dates_list": current_month_date_list,
|
|
"data": paginator_qry(data, request.GET.get("page")),
|
|
}
|
|
return render(
|
|
request, "attendance/work_record/work_record_list.html", context=context
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required("attendance.add_attendancegeneralsetting")
|
|
def enable_timerunner(request):
|
|
"""
|
|
This method is used to enable/disable the timerunner feature
|
|
"""
|
|
|
|
time_runner = AttendanceGeneralSetting.objects.first()
|
|
time_runner = time_runner if time_runner else AttendanceGeneralSetting()
|
|
time_runner.time_runner = "time_runner" in request.GET.keys()
|
|
time_runner.save()
|
|
return HttpResponse("success")
|