[UPDT] ATTENDANCE: Work record colored view and export option
This commit is contained in:
@@ -1,4 +1,31 @@
|
||||
{% load i18n %} {% load attendancefilters %}
|
||||
<div class="d-flex justify-content-between m-2 ms-0">
|
||||
<button class="oh-btn oh-btn--secondary" data-toggle="oh-modal-toggle" data-target="#exportRecords" onclick="window.location.href = `{% url 'work-record-export' %}?month={{leave_dates.0.month}}&year={{leave_dates.0.year}}`">
|
||||
<ion-icon name="download-outline" class="mr-1 md hydrated" role="img" aria-label="download"></ion-icon>{% trans "Export" %}
|
||||
</button>
|
||||
<div class="d-flex flex-row-reverse m-2">
|
||||
<span class="" style="margin-left: 10px;">
|
||||
<span class="oh-dot oh-dot--small me-1" style="background-color:#ed4c4c"></span>
|
||||
{% trans "Conflict" %}
|
||||
</span>
|
||||
<span class="me-3" style="margin-left: 10px;">
|
||||
<span class="oh-dot oh-dot--small me-1" style="background-color:#a8b1ff"></span>
|
||||
{% trans "Expected Working" %}
|
||||
</span>
|
||||
<span class="me-3" style="margin-left: 10px;">
|
||||
<span class="oh-dot oh-dot--small me-1" style="background-color:#808080"></span>
|
||||
{% trans "Absent" %}
|
||||
</span>
|
||||
<span class="me-3" style="margin-left: 10px;">
|
||||
<span class="oh-dot oh-dot--small me-1" style="background-color:#dfdf52"></span>
|
||||
{% trans "Half Day Present" %}
|
||||
</span>
|
||||
<span class="me-3" style="margin-left: 10px;">
|
||||
<span class="oh-dot oh-dot--small me-1" style="background-color:#38c338"></span>
|
||||
{% trans "Present" %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table">
|
||||
<table>
|
||||
<thead>
|
||||
|
||||
@@ -50,53 +50,25 @@
|
||||
<div>
|
||||
<h4>{% trans "Work Records" %}</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="me-3 d-flex flex-row-reverse align-items-center" >
|
||||
<div>
|
||||
<h6 class="mb-2 fw-bold">{% trans "Date:" %} {{ current_date }}</h6>
|
||||
<h6>
|
||||
<div style = "cursor: pointer;">
|
||||
<label for="monthYearField" class="text-danger fw-bold" style = "cursor: pointer;">{% trans "Month" %}</label>
|
||||
<input class="oh-select p-2 w-75 m-1"
|
||||
type="month"
|
||||
id="monthYearField"
|
||||
value="{{ current_date|date:"Y-m" }}"
|
||||
name="month"
|
||||
hx-get="{% url 'work-records-change-month' %}"
|
||||
hx-target="#workRecordTable"
|
||||
hx-trigger="input">
|
||||
</div>
|
||||
</h6>
|
||||
</div>
|
||||
<div style="width:250px">
|
||||
<div class="d-flex oh-wrapper" style="align-items: center">
|
||||
<div>
|
||||
<div class="draft me-3" style="margin-left: 5px; margin-bottom:5px">
|
||||
<div class="oh-dot oh-dot--small me-1" style="background-color: #a8b1ff;"></div>
|
||||
{% trans "Expected Working" %}
|
||||
</div>
|
||||
<div class="review_ongoing me-3" onclick="$('[name=status]').val('review_ongoing'); $('[name=status]').first().change(); $('.filterButton').click()" style=" margin-left: 5px; margin-bottom:5px">
|
||||
<div class="oh-dot oh-dot--small me-1" style="background-color: #dfdf52;"></div>
|
||||
{% trans "Half Day Present" %}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="confirmed me-3" onclick="$('[name=status]').val('confirmed'); $('[name=status]').first().change(); $('.filterButton').click()" style=" margin-left: 5px; margin-bottom:5px">
|
||||
<div class="oh-dot oh-dot--small me-1" style="background-color: #38c338;"></div>
|
||||
{% trans "Present" %}
|
||||
</div>
|
||||
<div class="paid me-3" onclick="$('[name=status]').val('paid'); $('[name=status]').first().change(); $('.filterButton').click()" style=" margin-left: 5px; margin-bottom:5px">
|
||||
<div class="oh-dot oh-dot--small me-1" style="background-color: #808080;"></div>
|
||||
{% trans "Absent" %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="me-3" >
|
||||
<h6 class="mb-2 fw-bold">{% trans "Date:" %} {{ current_date }}</h6>
|
||||
<h6>
|
||||
<div style = "cursor: pointer;">
|
||||
<label for="monthYearField" class="text-danger fw-bold" style = "cursor: pointer;">{% trans "Month" %}</label>
|
||||
<input class="oh-select p-2 w-75 m-1"
|
||||
type="month"
|
||||
id="monthYearField"
|
||||
value="{{ current_date|date:"Y-m" }}"
|
||||
name="month"
|
||||
hx-get="{% url 'work-records-change-month' %}"
|
||||
hx-target="#workRecordTable"
|
||||
hx-trigger="input">
|
||||
</div>
|
||||
</div>
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div id="workRecordTable">
|
||||
{% include "attendance/work_record/work_record_list.html" %}
|
||||
<div id="workRecordTable" hx-get="{% url 'work-records-change-month' %}?month={{ current_date|date:"Y-m" }}" hx-trigger="load">
|
||||
<div class="animated-background"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -364,6 +364,7 @@ urlpatterns = [
|
||||
name="delete-comment-file",
|
||||
),
|
||||
path("work-records/", views.work_records, name="work-records"),
|
||||
path("work-record-export/", views.work_record_export, name="work-record-export"),
|
||||
path(
|
||||
"work-records-change-month",
|
||||
views.work_records_change_month,
|
||||
|
||||
@@ -13,6 +13,7 @@ provide the main entry points for interacting with the application's functionali
|
||||
|
||||
import calendar
|
||||
import contextlib
|
||||
import io
|
||||
import json
|
||||
from datetime import date, datetime, timedelta
|
||||
from urllib.parse import parse_qs
|
||||
@@ -1954,8 +1955,6 @@ def monthly_leave_days(month, year):
|
||||
based_on_week = company_leave.based_on_week
|
||||
based_on_week_day = company_leave.based_on_week_day
|
||||
if based_on_week != None:
|
||||
|
||||
# Set Sunday as the first day of the week
|
||||
calendar.setfirstweekday(6)
|
||||
month_calendar = calendar.monthcalendar(year, month)
|
||||
weeks = month_calendar[int(based_on_week)]
|
||||
@@ -1968,9 +1967,8 @@ def monthly_leave_days(month, year):
|
||||
date_name.weekday() == int(based_on_week_day)
|
||||
and date_name not in leave_dates
|
||||
):
|
||||
leave_dates.append(date_name.day)
|
||||
leave_dates.append(date_name)
|
||||
else:
|
||||
# Set Monday as the first day of the week
|
||||
calendar.setfirstweekday(0)
|
||||
month_calendar = calendar.monthcalendar(year, month)
|
||||
for week in month_calendar:
|
||||
@@ -2087,6 +2085,119 @@ def work_records_change_month(request):
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("leave.add_leaverequest")
|
||||
def work_record_export(request):
|
||||
month = int(request.GET.get("month", date.today().month))
|
||||
year = int(request.GET.get("year", date.today().year))
|
||||
records = WorkRecord.objects.filter(date__month=month, date__year=year)
|
||||
num_days = calendar.monthrange(year, month)[1]
|
||||
all_date_objects = [date(year, month, day) for day in range(1, num_days + 1)]
|
||||
leave_dates = monthly_leave_days(month, year)
|
||||
data_rows = []
|
||||
data = ["Employee"]
|
||||
if info := request.user.employee_get.employee_work_info:
|
||||
try:
|
||||
employee_company = info.company_id
|
||||
date_format = (
|
||||
employee_company.date_format
|
||||
if employee_company and employee_company.date_format
|
||||
else "DD-MM-YYYY"
|
||||
)
|
||||
except:
|
||||
date_format = "DD-MM-YYYY"
|
||||
else:
|
||||
date_format = "DD-MM-YYYY"
|
||||
|
||||
# Define date formats
|
||||
date_formats = {
|
||||
"DD-MM-YYYY": "%d-%m-%Y",
|
||||
"DD.MM.YYYY": "%d.%m.%Y",
|
||||
"DD/MM/YYYY": "%d/%m/%Y",
|
||||
"MM/DD/YYYY": "%m/%d/%Y",
|
||||
"YYYY-MM-DD": "%Y-%m-%d",
|
||||
"YYYY/MM/DD": "%Y/%m/%d",
|
||||
"MMMM D, YYYY": "%B %d, %Y",
|
||||
"DD MMMM, YYYY": "%d %B, %Y",
|
||||
"MMM. D, YYYY": "%b. %d, %Y",
|
||||
"D MMM. YYYY": "%d %b. %Y",
|
||||
"dddd, MMMM D, YYYY": "%A, %B %d, %Y",
|
||||
}
|
||||
|
||||
format_string = date_formats[date_format]
|
||||
|
||||
for employee in Employee.objects.all():
|
||||
row_data = {"Employee": employee}
|
||||
for date_item in all_date_objects:
|
||||
for record in records:
|
||||
if date_item <= date.today() and date_item not in leave_dates:
|
||||
date_item_string = date_item.strftime(format_string)
|
||||
if employee == record.employee_id:
|
||||
row_data[str(record.date.strftime(format_string))] = (
|
||||
record.work_record_type
|
||||
)
|
||||
else:
|
||||
row_data[str(date_item_string)] = "EW"
|
||||
|
||||
data_rows.append(row_data)
|
||||
|
||||
for date_item in all_date_objects:
|
||||
data.append(str(date_item.strftime(format_string)))
|
||||
|
||||
data_frame = pd.DataFrame(data_rows, columns=data)
|
||||
|
||||
output = io.BytesIO()
|
||||
with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
|
||||
data_frame.to_excel(writer, index=False, sheet_name="Sheet1")
|
||||
|
||||
workbook = writer.book
|
||||
worksheet = writer.sheets["Sheet1"]
|
||||
|
||||
format_abs = workbook.add_format(
|
||||
{"bg_color": "#808080", "font_color": "#ffffff"}
|
||||
)
|
||||
format_fdp = workbook.add_format(
|
||||
{"bg_color": "#38c338", "font_color": "#ffffff"}
|
||||
)
|
||||
format_hdp = workbook.add_format(
|
||||
{"bg_color": "#dfdf52", "font_color": "#000000"}
|
||||
)
|
||||
format_conf = workbook.add_format(
|
||||
{"bg_color": "#ed4c4c", "font_color": "#ffffff"}
|
||||
)
|
||||
format_ew = workbook.add_format(
|
||||
{"bg_color": "#a8b1ff", "font_color": "#ffffff"}
|
||||
)
|
||||
|
||||
for row_num in range(1, len(data_frame) + 1):
|
||||
for col_num in range(1, len(data_frame.columns)):
|
||||
cell_value = data_frame.iloc[row_num - 1, col_num]
|
||||
if cell_value == "ABS":
|
||||
worksheet.write(row_num, col_num, cell_value, format_abs)
|
||||
elif cell_value == "FDP":
|
||||
worksheet.write(row_num, col_num, cell_value, format_fdp)
|
||||
elif cell_value == "HDP":
|
||||
worksheet.write(row_num, col_num, cell_value, format_hdp)
|
||||
elif cell_value == "CONF":
|
||||
worksheet.write(row_num, col_num, cell_value, format_conf)
|
||||
elif cell_value == "EW":
|
||||
worksheet.write(row_num, col_num, cell_value, format_ew)
|
||||
|
||||
for i, col in enumerate(data_frame.columns):
|
||||
column_len = max(data_frame[col].astype(str).map(len).max(), len(col))
|
||||
worksheet.set_column(i, i, column_len)
|
||||
|
||||
output.seek(0)
|
||||
|
||||
response = HttpResponse(
|
||||
output.read(),
|
||||
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
)
|
||||
response["Content-Disposition"] = 'attachment; filename="work_record_export.xlsx"'
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("attendance.add_attendancegeneralsetting")
|
||||
def enable_timerunner(request):
|
||||
|
||||
Reference in New Issue
Block a user