416 lines
18 KiB
HTML
416 lines
18 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Schedule Assignment Details - HR{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- BEGIN breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'hr:dashboard' %}">HR</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'hr:schedule_assignment_list' %}">Schedule Assignments</a></li>
|
|
<li class="breadcrumb-item active">Assignment Details</li>
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">
|
|
Schedule Assignment Details
|
|
<small>{{ object.employee.get_full_name }} - {{ object.schedule.name }}</small>
|
|
</h1>
|
|
<!-- END page-header -->
|
|
|
|
<div class="row">
|
|
<div class="col-xl-8">
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Assignment Information</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'hr:schedule_assignment_update' object.pk %}" class="btn btn-xs btn-primary me-2">
|
|
<i class="fa fa-edit"></i> Edit
|
|
</a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold" width="150">Employee:</td>
|
|
<td>
|
|
<a href="{% url 'hr:employee_detail' object.employee.pk %}" class="text-decoration-none">
|
|
{{ object.employee.get_full_name }}
|
|
</a>
|
|
<div class="small text-muted">{{ object.employee.employee_id }}</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Department:</td>
|
|
<td>{{ object.employee.department.name }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Position:</td>
|
|
<td>{{ object.employee.position }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Schedule:</td>
|
|
<td>
|
|
<a href="{% url 'hr:schedule_detail' object.schedule.pk %}" class="text-decoration-none">
|
|
{{ object.schedule.name }}
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Schedule Type:</td>
|
|
<td>
|
|
<span class="badge bg-primary">{{ object.schedule.get_schedule_type_display }}</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold" width="150">Start Date:</td>
|
|
<td>{{ object.start_date|date:"M d, Y" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">End Date:</td>
|
|
<td>{{ object.end_date|date:"M d, Y"|default:"Ongoing" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Status:</td>
|
|
<td>
|
|
<span class="badge bg-{% if object.status == 'ACTIVE' %}success{% elif object.status == 'PENDING' %}warning{% else %}secondary{% endif %}">
|
|
{{ object.get_status_display }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Assigned By:</td>
|
|
<td>{{ object.assigned_by.get_full_name }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Assigned On:</td>
|
|
<td>{{ object.assigned_at|date:"M d, Y H:i" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{% if object.notes %}
|
|
<div class="mt-4">
|
|
<h6>Assignment Notes</h6>
|
|
<div class="bg-light p-3 rounded">
|
|
{{ object.notes|linebreaks }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Schedule Details</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6>Working Hours</h6>
|
|
<table class="table table-sm table-bordered">
|
|
<thead>
|
|
<tr>
|
|
<th>Day</th>
|
|
<th>Start Time</th>
|
|
<th>End Time</th>
|
|
<th>Hours</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for day in object.schedule.working_days %}
|
|
<tr>
|
|
<td class="fw-bold">{{ day.day_name }}</td>
|
|
<td>{{ day.start_time|time:"H:i" }}</td>
|
|
<td>{{ day.end_time|time:"H:i" }}</td>
|
|
<td>{{ day.total_hours }}h</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Schedule Summary</h6>
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold" width="150">Total Hours/Week:</td>
|
|
<td>{{ object.schedule.total_weekly_hours }}h</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Working Days:</td>
|
|
<td>{{ object.schedule.working_days_count }} days</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Break Duration:</td>
|
|
<td>{{ object.schedule.break_duration|default:"Not specified" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Overtime Policy:</td>
|
|
<td>{{ object.schedule.overtime_policy|default:"Standard" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Recent Time Entries</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'hr:time_entry_list' %}?employee={{ object.employee.pk }}" class="btn btn-xs btn-primary">
|
|
<i class="fa fa-clock"></i> View All
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if recent_time_entries %}
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Clock In</th>
|
|
<th>Clock Out</th>
|
|
<th>Total Hours</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for entry in recent_time_entries %}
|
|
<tr>
|
|
<td>{{ entry.date|date:"M d, Y" }}</td>
|
|
<td>{{ entry.clock_in|time:"H:i"|default:"--" }}</td>
|
|
<td>{{ entry.clock_out|time:"H:i"|default:"--" }}</td>
|
|
<td>{{ entry.total_hours|floatformat:2 }}h</td>
|
|
<td>
|
|
<span class="badge bg-{% if entry.status == 'APPROVED' %}success{% elif entry.status == 'PENDING' %}warning{% else %}secondary{% endif %}">
|
|
{{ entry.get_status_display }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center text-muted py-3">
|
|
<i class="fa fa-clock fa-2x mb-2"></i>
|
|
<div>No recent time entries found</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
</div>
|
|
|
|
<div class="col-xl-4">
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Quick Actions</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="d-grid gap-2">
|
|
<a href="{% url 'hr:schedule_assignment_update' object.pk %}" class="btn btn-primary">
|
|
<i class="fa fa-edit me-2"></i>Edit Assignment
|
|
</a>
|
|
|
|
{% if object.status == 'PENDING' %}
|
|
<button class="btn btn-success" onclick="activateAssignment()">
|
|
<i class="fa fa-check me-2"></i>Activate Assignment
|
|
</button>
|
|
{% endif %}
|
|
|
|
{% if object.status == 'ACTIVE' %}
|
|
<button class="btn btn-warning" onclick="suspendAssignment()">
|
|
<i class="fa fa-pause me-2"></i>Suspend Assignment
|
|
</button>
|
|
{% endif %}
|
|
|
|
<a href="{% url 'hr:time_entry_create' %}?employee={{ object.employee.pk }}" class="btn btn-info">
|
|
<i class="fa fa-clock me-2"></i>Add Time Entry
|
|
</a>
|
|
|
|
<button class="btn btn-secondary" onclick="duplicateAssignment()">
|
|
<i class="fa fa-copy me-2"></i>Duplicate Assignment
|
|
</button>
|
|
|
|
<hr>
|
|
|
|
<a href="{% url 'hr:schedule_assignment_delete' object.pk %}" class="btn btn-danger">
|
|
<i class="fa fa-trash me-2"></i>Delete Assignment
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Assignment Statistics</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row text-center">
|
|
<div class="col-6">
|
|
<div class="fs-20px fw-bold text-primary">{{ object.days_active }}</div>
|
|
<div class="small text-muted">Days Active</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="fs-20px fw-bold text-success">{{ object.total_hours_worked }}</div>
|
|
<div class="small text-muted">Hours Worked</div>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div class="row text-center">
|
|
<div class="col-6">
|
|
<div class="fs-20px fw-bold text-warning">{{ object.attendance_rate }}%</div>
|
|
<div class="small text-muted">Attendance Rate</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="fs-20px fw-bold text-info">{{ object.overtime_hours }}</div>
|
|
<div class="small text-muted">Overtime Hours</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Employee Information</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="flex-fill">
|
|
<div class="fw-bold">{{ object.employee.get_full_name }}</div>
|
|
<div class="small text-muted">{{ object.employee.employee_id }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<table class="table table-borderless table-sm">
|
|
<tr>
|
|
<td class="fw-bold" width="80">Email:</td>
|
|
<td><a href="mailto:{{ object.employee.email }}">{{ object.employee.email }}</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Phone:</td>
|
|
<td>{{ object.employee.phone|default:"Not provided" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Hire Date:</td>
|
|
<td>{{ object.employee.hire_date|date:"M d, Y" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Status:</td>
|
|
<td>
|
|
<span class="badge bg-{% if object.employee.status == 'ACTIVE' %}success{% else %}secondary{% endif %}">
|
|
{{ object.employee.get_status_display }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div class="d-grid">
|
|
<a href="{% url 'hr:employee_detail' object.employee.pk %}" class="btn btn-outline-primary btn-sm">
|
|
<i class="fa fa-user me-2"></i>View Employee Profile
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
function activateAssignment() {
|
|
if (confirm('Activate this schedule assignment?')) {
|
|
$.ajax({
|
|
url: '{% url "hr:schedule_assignment_activate" object.pk %}',
|
|
method: 'POST',
|
|
data: {
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
toastr.success('Assignment activated successfully');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to activate assignment');
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('An error occurred while activating the assignment');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function suspendAssignment() {
|
|
if (confirm('Suspend this schedule assignment?')) {
|
|
$.ajax({
|
|
url: '{% url "hr:schedule_assignment_suspend" object.pk %}',
|
|
method: 'POST',
|
|
data: {
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
toastr.success('Assignment suspended successfully');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to suspend assignment');
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('An error occurred while suspending the assignment');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function duplicateAssignment() {
|
|
if (confirm('Create a copy of this assignment?')) {
|
|
$.ajax({
|
|
url: '{% url "hr:schedule_assignment_duplicate" object.pk %}',
|
|
method: 'POST',
|
|
data: {
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
toastr.success('Assignment duplicated successfully');
|
|
window.location.href = response.redirect_url;
|
|
} else {
|
|
toastr.error('Failed to duplicate assignment');
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('An error occurred while duplicating the assignment');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|