[UPDT] ATTENDANCE: Attendance request save function

This commit is contained in:
Horilla
2023-10-09 16:16:44 +05:30
parent a7b56aad01
commit d285768b03
7 changed files with 332 additions and 289 deletions

View File

@@ -237,6 +237,10 @@ class Attendance(models.Model):
prev_attendance_approved = False
condition = AttendanceValidationCondition.objects.first()
if self.is_validate_request:
self.is_validate_request_approved = False
self.attendance_validated = False
if condition is not None and condition.overtime_cutoff is not None:
overtime_cutoff = condition.overtime_cutoff
cutoff_seconds = strtime_seconds(overtime_cutoff)

View File

@@ -1,10 +1,6 @@
{% extends 'index.html' %}
{% block content %}
{% load static %}
{% load i18n %}
{% load basefilters %}
{% if perms.attendance.add_attendance or request.user|is_reportingmanager %}
{% extends 'index.html' %} {% block content %} {% load static %} {% load i18n %}
{% load basefilters %} {% if perms.attendance.add_attendance or request.user|is_reportingmanager %}
<div
class="oh-modal"
id="addAttendance"
@@ -17,11 +13,7 @@
<h2 class="oh-modal__dialog-title" id="addEmployeeModalLabel">
{% trans "Add Attendances" %}
</h2>
<button
class="oh-modal__close"
aria-label="Close"
>
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
@@ -32,40 +24,41 @@
<section class="oh-wrapper oh-main__topbar" x-data="{searchShow: false}">
<div class="oh-main__titlebar oh-main__titlebar--left">
<h1 class="oh-main__titlebar-title fw-bold">
{% trans "Attendances" %}
</h1>
<h1 class="oh-main__titlebar-title fw-bold">{% trans "Attendances" %}</h1>
</div>
<div class="oh-main__titlebar oh-main__titlebar--right">
<div class="oh-main__titlebar-button-container">
{% if perms.attendance.add_attendance or request.user|is_reportingmanager%}
<button
class="oh-btn oh-btn--secondary ml-2"
data-toggle="oh-modal-toggle"
data-target="#addAttendance"
hx-get="{% url 'attendance-create' %}"
hx-target="#addAttendanceModalBody"
>
<ion-icon name="add-sharp" class="mr-1"></ion-icon>{% trans "Create" %}
</button>
<button
class="oh-btn oh-btn--secondary ml-2"
data-toggle="oh-modal-toggle"
data-target="#addAttendance"
hx-get="{% url 'attendance-create' %}"
hx-target="#addAttendanceModalBody"
>
<ion-icon name="add-sharp" class="mr-1"></ion-icon>{% trans "Create" %}
</button>
{% endif %}
</div>
</div>
</section>
<div
class="oh-wrapper-main"
>
<div class="oh-wrapper-main">
<main :class="sidebarOpen ? 'oh-main__sidebar-visible' : ''">
<div class="oh-wrapper">
<div class="oh-404">
<img style=" width: 190px;height: 200px;" src="{% static 'images/ui/present.png' %}" class="oh-404__image mb-4" alt="Page not found. 404."/>
<h5 class="oh-404__subtitle">{% trans "There are no attendance records to display." %}</h5>
<img
style="width: 190px; height: 200px"
src="{% static 'images/ui/present.png' %}"
class="oh-404__image mb-4"
alt="Page not found. 404."
/>
<h5 class="oh-404__subtitle">
{% trans "There are no attendance records to display." %}
</h5>
</div>
</div>
</main>
</div>
</div>
{% endblock content %}
{% endblock content %}

View File

@@ -1,165 +1,183 @@
{% load static %}
{% load i18n %}
<form hx-get='{% url "attendance-search" %}' id="filterForm" hx-swap='innerHTML' hx-target='#tab_contents' >
{% load static %} {% load i18n %}
<form
hx-get='{% url "attendance-search" %}'
id="filterForm"
hx-swap="innerHTML"
hx-target="#tab_contents"
>
<div class="oh-dropdown__filter-body">
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Work Info" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Employee" %}</label>
{{f.form.employee_id}}
<div class="oh-accordion-header">{% trans "Work Info" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Employee" %}</label>
{{f.form.employee_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Department" %}</label>
{{f.form.employee_id__employee_work_info__department_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Shift" %}</label>
{{f.form.shift_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Reporting Manager" %}</label>
{{f.form.employee_id__employee_work_info__reporting_manager_id}}
</div>
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Department" %}</label>
{{f.form.employee_id__employee_work_info__department_id}}
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Company" %}</label>
{{f.form.employee_id__employee_work_info__company_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Job Position" %}</label>
{{f.form.employee_id__employee_work_info__job_position_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Work Type" %}</label>
{{f.form.work_type_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Work Location" %}</label>
{{f.form.employee_id__employee_work_info__location}}
</div>
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Shift" %}</label>
{{f.form.shift_id}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Reporting Manager" %}</label>
{{f.form.employee_id__employee_work_info__reporting_manager_id}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Company" %}</label>
{{f.form.employee_id__employee_work_info__company_id}}
</div>
</div>
{% comment %} {{f.form}} {% endcomment %}
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Attendance" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Attendance Date" %}</label>
{{f.form.attendance_date}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "In Time" %}</label>
{{f.form.attendance_clock_in}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Validated?" %}</label>
{{f.form.attendance_validated}}
</div>
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Job Position" %}</label>
{{f.form.employee_id__employee_work_info__job_position_id}}
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Min Hour" %}</label>
{{f.form.minimum_hour}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Out Time" %}</label>
{{f.form.attendance_clock_out}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "OT Approved?" %}</label>
{{f.form.attendance_overtime_approve}}
</div>
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Work Type" %}</label>
{{f.form.work_type_id}}
</div>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Attendance From" %}</label>
{{f.form.attendance_date__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "In From" %}</label>
{{f.form.attendance_clock_in__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Out From" %}</label>
{{f.form.attendance_clock_out__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label"
>{% trans "At Work Greater or Equal" %}</label
>
{{f.form.at_work_second__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "OT Greater or Equal" %}</label>
{{f.form.overtime_second__gte}}
</div>
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Work Location" %}</label>
{{f.form.employee_id__employee_work_info__location}}
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Attendance Till" %}</label>
{{f.form.attendance_date__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "In Till" %}</label>
{{f.form.attendance_clock_in__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Out Till" %}</label>
{{f.form.attendance_clock_out__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label"
>{% trans "At Work Less Than or Equal" %}</label
>
{{f.form.at_work_second__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label"
>{% trans "OT Less Than or Equal" %}</label
>
{{f.form.overtime_second__lte}}
</div>
</div>
</div>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Group By" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Field" %}</label>
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<select
class="oh-select mt-1"
id="id_field"
name="field"
class="select2-selection select2-selection--single"
id="gp"
>
{% for field in gp_fields %}
<option value="{{ field.0 }}">{% trans field.1 %}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</div>
</div>
{% comment %} {{f.form}} {% endcomment %}
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Attendance" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Attendance Date" %}</label>
{{f.form.attendance_date}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "In Time" %}</label>
{{f.form.attendance_clock_in}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Validated?" %}</label>
{{f.form.attendance_validated}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Min Hour" %}</label>
{{f.form.minimum_hour}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Out Time" %}</label>
{{f.form.attendance_clock_out}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "OT Approved?" %}</label>
{{f.form.attendance_overtime_approve}}
</div>
</div>
</div>
</div>
<div class="oh-dropdown__filter-footer">
<button
class="oh-btn oh-btn--secondary oh-btn--small w-100 filterButton"
id="filterSubmit"
>
{% trans "Filter" %}
</button>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Advanced" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Attendance From" %}</label>
{{f.form.attendance_date__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "In From" %}</label>
{{f.form.attendance_clock_in__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Out From" %}</label>
{{f.form.attendance_clock_out__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "At Work Greater or Equal" %}</label>
{{f.form.at_work_second__gte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "OT Greater or Equal" %}</label>
{{f.form.overtime_second__gte}}
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Attendance Till" %}</label>
{{f.form.attendance_date__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "In Till" %}</label>
{{f.form.attendance_clock_in__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "Out Till" %}</label>
{{f.form.attendance_clock_out__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "At Work Less Than or Equal" %}</label>
{{f.form.at_work_second__lte}}
</div>
<div class="oh-input-group">
<label class="oh-label">{% trans "OT Less Than or Equal" %}</label>
{{f.form.overtime_second__lte}}
</div>
</div>
</div>
</div>
</div>
<div class="oh-accordion">
<div class="oh-accordion-header">{% trans "Group By" %}</div>
<div class="oh-accordion-body">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">{% trans "Field" %}</label>
</div>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<select class="oh-select mt-1 " id="id_field" name="field" class="select2-selection select2-selection--single" id="gp">
{% for field in gp_fields %}
<option value="{{ field.0 }}">{% trans field.1 %}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="oh-dropdown__filter-footer">
<button class="oh-btn oh-btn--secondary oh-btn--small w-100 filterButton" id="filterSubmit">{% trans "Filter" %}</button>
</div>
</form>
<script src="{% static '/base/filter.js' %}"></script>
<script src="{% static '/base/filter.js' %}"></script>

View File

@@ -1,23 +1,23 @@
{% load static %} {% load i18n %} {% load basefilters %} {% if perms.attendance.add_attendance or request.user|is_reportingmanager %}
{% load static %} {% load i18n %} {% load basefilters %}
{% if perms.attendance.add_attendance or request.user|is_reportingmanager %}
<style>
.loader-container {
position: relative;
width: 120px;
height: 120px;
margin-left: 199px;
}
.loader {
border: 10px solid #f3f3f3;
border-radius: 50%;
border-top: 10px solid #A4A3A3;
border-top: 10px solid #a4a3a3;
width: 100%;
height: 100%;
-webkit-animation: spin 2s linear infinite; /* Safari */
animation: spin 2s linear infinite;
}
.loader-text {
position: absolute;
top: 52%;
@@ -27,18 +27,26 @@
font-weight: bold;
color: #000;
}
/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</style>
<div
class="oh-modal"
id="addAttendance"
@@ -84,27 +92,31 @@
id="attendanceImportForm"
>
{% csrf_token %}
<div class = "oh-modal__dialog-body mr-5" id="uploading" style="display:none">
<div class="loader-container">
<div class="loader"></div>
<div class="loader-text">{% trans "Uploading..." %}</div>
</div>
</div>
<div id="uploadContainer">
<label class="oh-dropdown__import-label" for="uploadFile">
<ion-icon
name="cloud-upload"
class="oh-dropdown__import-form-icon"
></ion-icon>
<span class="oh-dropdown__import-form-title"
>{% trans "Upload a File" %}</span
>
<span class="oh-dropdown__import-form-text"
>{% trans "Drag and drop files here" %}</span
>
</label>
<input type="file" name="attendance_import" id="" required/>
<div
class="oh-modal__dialog-body mr-5"
id="uploading"
style="display: none"
>
<div class="loader-container">
<div class="loader"></div>
<div class="loader-text">{% trans "Uploading..." %}</div>
</div>
</div>
<div id="uploadContainer">
<label class="oh-dropdown__import-label" for="uploadFile">
<ion-icon
name="cloud-upload"
class="oh-dropdown__import-form-icon"
></ion-icon>
<span class="oh-dropdown__import-form-title"
>{% trans "Upload a File" %}</span
>
<span class="oh-dropdown__import-form-text"
>{% trans "Drag and drop files here" %}</span
>
</label>
<input type="file" name="attendance_import" id="" required />
</div>
<button
type="submit"
class="oh-btn oh-btn--small oh-btn--secondary w-100 mt-3"
@@ -134,15 +146,19 @@
<div
class="oh-modal__dialog-body p-0 pt-2"
id="attendanceExportModalBody"
>
<form
action="{%url 'attendance-info-export' %}"
method="get"
onsubmit="event.stopPropagation();$(this).parents().find('.oh-modal--show').last().toggleClass('oh-modal--show');"
id="attendanceExportForm"
>
<form action="{%url 'attendance-info-export' %}"
method="get"
onsubmit="event.stopPropagation();$(this).parents().find('.oh-modal--show').last().toggleClass('oh-modal--show');"
id="attendanceExportForm">
{% csrf_token %}
{% include 'attendance/attendance/export_filter.html' %}
{% csrf_token %} {% include 'attendance/attendance/export_filter.html'
%}
<div class="oh-dropdown__filter-footer">
<button class="oh-btn oh-btn--secondary oh-btn--small w-100 ">{% trans "Export" %}</button>
<button class="oh-btn oh-btn--secondary oh-btn--small w-100">
{% trans "Export" %}
</button>
</div>
</form>
</div>
@@ -222,61 +238,64 @@
>
<ul class="oh-dropdown__items">
{% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link"
id="attendance-info-import"
data-toggle="oh-modal-toggle"
data-target="#attendanceImport"
>{% trans "Import" %}</a
>
</li>
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link"
id="attendance-info-export"
data-toggle="oh-modal-toggle"
data-target="#attendanceExport"
>{% trans "Export" %}</a
>
</li>
{% endif %} {% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
<li class="oh-dropdown__item">
<a href="#" id="validateAttendances" class="oh-dropdown__link"
>{% trans "Validate" %}</a
>
</li>
{% endif %} {% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
<li class="oh-dropdown__item">
<a href="#" id="approveOt" class="oh-dropdown__link"
>{% trans "Approve OT" %}</a
>
</li>
{% endif %} {% if perms.attendance.delete_attendance %}
<li class="oh-dropdown__item">
<a
href="#"
id="bulkDelete"
class="oh-dropdown__link oh-dropdown__link--danger"
>{% trans "Delete" %}</a
>
</li>
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link"
id="attendance-info-import"
data-toggle="oh-modal-toggle"
data-target="#attendanceImport"
>{% trans "Import" %}</a
>
</li>
<li class="oh-dropdown__item">
<a
href="#"
class="oh-dropdown__link"
id="attendance-info-export"
data-toggle="oh-modal-toggle"
data-target="#attendanceExport"
>{% trans "Export" %}</a
>
</li>
{% endif %}
{% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
<li class="oh-dropdown__item">
<a href="#" id="validateAttendances" class="oh-dropdown__link"
>{% trans "Validate" %}</a
>
</li>
{% endif %}
{% if perms.attendance.change_attendance or request.user|is_reportingmanager %}
<li class="oh-dropdown__item">
<a href="#" id="approveOt" class="oh-dropdown__link"
>{% trans "Approve OT" %}</a
>
</li>
{% endif %}
{% if perms.attendance.delete_attendance %}
<li class="oh-dropdown__item">
<a
href="#"
id="bulkDelete"
class="oh-dropdown__link oh-dropdown__link--danger"
>{% trans "Delete" %}</a
>
</li>
{% endif %}
</ul>
</div>
</div>
{% if perms.attendance.add_attendance or request.user|is_reportingmanager%}
<button
class="oh-btn oh-btn--secondary ml-2"
data-toggle="oh-modal-toggle"
data-target="#addAttendance"
hx-get="{% url 'attendance-create' %}"
hx-target="#addAttendanceModalBody"
>
<ion-icon name="add-sharp" class="mr-1"></ion-icon>{% trans "Create" %}
</button>
<button
class="oh-btn oh-btn--secondary ml-2"
data-toggle="oh-modal-toggle"
data-target="#addAttendance"
hx-get="{% url 'attendance-create' %}"
hx-target="#addAttendanceModalBody"
>
<ion-icon name="add-sharp" class="mr-1"></ion-icon>{% trans "Create" %}
</button>
{% endif %}
</div>
</div>

View File

@@ -7,18 +7,19 @@
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label">
<input type="checkbox" id="select-all-fields" /> {% trans "Select All" %}
<input type="checkbox" id="select-all-fields" /> {% trans "Select
All" %}
</label>
</div>
</div>
</div>
<div class="row">
{% for field in export_form.selected_fields %}
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label"> {{ field }} </label>
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="oh-input-group">
<label class="oh-label"> {{ field }} </label>
</div>
</div>
{% endfor %}
</div>
</div>

View File

@@ -1,3 +1,6 @@
"""Module for handling attendance error data."""
def handle_attendance_errors(error_list):
"""
Reorganize a list of error dictionaries into a structured error data dictionary
@@ -41,14 +44,17 @@ def handle_attendance_errors(error_list):
"Error17": [],
}
for item in error_list:
for key in error_data.keys():
for key, value in error_data.items():
if key in item:
error_data[key].append(item[key])
value.append(item[key])
else:
error_data[key].append(None)
for key, value in error_data.items():
if all(v is None for v in value):
keys_to_remove.append(key)
value.append(None)
keys_to_remove = [
key for key, value in error_data.items() if all(v is None for v in value)
]
for key in keys_to_remove:
del error_data[key]
return error_data
return error_data

View File

@@ -1,12 +1,14 @@
"""
process_attendance_data.py
This module contains a function for processing attendance data
from Excel files and saving it to a database.
"""
from datetime import datetime
import pandas as pd
from employee.models import Employee
from attendance.models import Attendance
from base.models import EmployeeShift, WorkType
from employee.models import Employee
import pandas as pd
from datetime import datetime
def process_attendance_data(attendance_dicts):
@@ -166,4 +168,4 @@ def process_attendance_data(attendance_dicts):
attendance_data["Error17"] = f"{str(exception)}"
error_list.append(attendance_data)
return error_list
return error_list