400 lines
18 KiB
HTML
400 lines
18 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}
|
|
{% if object %}Edit Schedule Assignment{% else %}Create Schedule Assignment{% endif %}
|
|
{% endblock %}
|
|
|
|
{% block css %}
|
|
<!-- DateTimePicker CSS -->
|
|
<link href="{% static 'plugins/bootstrap-datepicker/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/bootstrap-timepicker/css/bootstrap-timepicker.min.css' %}" rel="stylesheet" />
|
|
<!-- Select2 CSS -->
|
|
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/select2-bootstrap-5-theme/dist/select2-bootstrap-5-theme.min.css' %}" rel="stylesheet" />
|
|
<style>
|
|
.help-sidebar {
|
|
background-color: #f8f9fa;
|
|
border-radius: 5px;
|
|
padding: 15px;
|
|
}
|
|
.shift-type-selector {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
margin-bottom: 15px;
|
|
}
|
|
.shift-type-option {
|
|
flex: 1;
|
|
min-width: 120px;
|
|
text-align: center;
|
|
padding: 15px 10px;
|
|
border: 2px solid #dee2e6;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
}
|
|
.shift-type-option.selected {
|
|
border-color: #2d62ed;
|
|
background-color: rgba(45, 98, 237, 0.1);
|
|
}
|
|
.conflict-warning {
|
|
background-color: #fff3cd;
|
|
border-left: 4px solid #ffc107;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
display: none;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- begin breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</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">
|
|
{% if object %}Edit Assignment{% else %}Create Assignment{% endif %}
|
|
</li>
|
|
</ol>
|
|
<!-- end breadcrumb -->
|
|
|
|
<!-- begin page-header -->
|
|
<h1 class="page-header">
|
|
{% if object %}Edit Schedule Assignment{% else %}Create Schedule Assignment{% endif %}
|
|
</h1>
|
|
<!-- end page-header -->
|
|
|
|
<!-- begin row -->
|
|
<div class="row">
|
|
<!-- begin col-8 -->
|
|
<div class="col-xl-8">
|
|
<!-- begin panel -->
|
|
<div class="panel panel-inverse">
|
|
<!-- begin panel-heading -->
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
{% if object %}Edit Assignment for {{ object.employee.get_full_name }}{% else %}Create New Assignment{% endif %}
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<!-- end panel-heading -->
|
|
|
|
<!-- begin panel-body -->
|
|
<div class="panel-body">
|
|
<!-- Conflict Warning -->
|
|
<div class="conflict-warning" id="conflict-warning">
|
|
<div class="d-flex">
|
|
<div class="me-3">
|
|
<i class="fas fa-exclamation-triangle fa-2x text-warning"></i>
|
|
</div>
|
|
<div>
|
|
<h5 class="mb-1">Potential Scheduling Conflict</h5>
|
|
<p class="mb-0" id="conflict-message">This employee already has an assignment during this time period.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="post" id="assignment-form">
|
|
{% csrf_token %}
|
|
|
|
<!-- Form Errors -->
|
|
{% if form.errors %}
|
|
<div class="alert alert-danger">
|
|
<h5><i class="fas fa-exclamation-circle"></i> Please correct the errors below:</h5>
|
|
<ul class="mb-0">
|
|
{% for field in form %}
|
|
{% for error in field.errors %}
|
|
<li>{{ field.label }}: {{ error }}</li>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% for error in form.non_field_errors %}
|
|
<li>{{ error }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Basic Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Basic Information</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="{{ form.schedule.id_for_label }}" class="form-label">Schedule <span class="text-danger">*</span></label>
|
|
{{ form.schedule }}
|
|
{% if form.schedule.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.schedule.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="{{ form.employee.id_for_label }}" class="form-label">Employee <span class="text-danger">*</span></label>
|
|
{{ form.employee }}
|
|
{% if form.employee.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.employee.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="{{ form.date.id_for_label }}" class="form-label">Date <span class="text-danger">*</span></label>
|
|
<div class="input-group">
|
|
{{ form.date }}
|
|
<span class="input-group-text"><i class="fas fa-calendar"></i></span>
|
|
</div>
|
|
{% if form.date.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.date.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="{{ form.status.id_for_label }}" class="form-label">Status</label>
|
|
{{ form.status }}
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.status.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Shift Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Shift Information</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Shift Type -->
|
|
<div class="mb-3">
|
|
<label for="{{ form.shift_type.id_for_label }}" class="form-label">Shift Type <span class="text-danger">*</span></label>
|
|
{{ form.shift_type }}
|
|
{% if form.shift_type.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.shift_type.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="{{ form.start_time.id_for_label }}" class="form-label">Start Time <span class="text-danger">*</span></label>
|
|
<div class="input-group">
|
|
{{ form.start_time }}
|
|
<span class="input-group-text"><i class="fas fa-clock"></i></span>
|
|
</div>
|
|
{% if form.start_time.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.start_time.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="{{ form.end_time.id_for_label }}" class="form-label">End Time <span class="text-danger">*</span></label>
|
|
<div class="input-group">
|
|
{{ form.end_time }}
|
|
<span class="input-group-text"><i class="fas fa-clock"></i></span>
|
|
</div>
|
|
{% if form.end_time.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.end_time.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="{{ form.hours.id_for_label }}" class="form-label">Hours</label>
|
|
{{ form.hours }}
|
|
{% if form.hours.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.hours.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="{{ form.location.id_for_label }}" class="form-label">Location</label>
|
|
{{ form.location }}
|
|
{% if form.location.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.location.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Additional Information</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label for="{{ form.notes.id_for_label }}" class="form-label">Notes</label>
|
|
{{ form.notes }}
|
|
{% if form.notes.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.notes.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="form-check mb-3">
|
|
{{ form.is_overtime }}
|
|
<label class="form-check-label" for="{{ form.is_overtime.id_for_label }}">
|
|
Overtime Assignment
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-check mb-3">
|
|
{{ form.is_on_call }}
|
|
<label class="form-check-label" for="{{ form.is_on_call.id_for_label }}">
|
|
On-Call Assignment
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="d-flex justify-content-between mt-4">
|
|
<a href="{% url 'hr:schedule_assignment_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-times"></i> Cancel
|
|
</a>
|
|
<div>
|
|
<button type="submit" name="save_and_add" class="btn btn-info me-2">
|
|
<i class="fas fa-save"></i> Save & Add Another
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save"></i> Save Assignment
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<!-- end panel-body -->
|
|
</div>
|
|
<!-- end panel -->
|
|
</div>
|
|
<!-- end col-8 -->
|
|
|
|
<!-- begin col-4 -->
|
|
<div class="col-xl-4">
|
|
<!-- Help Sidebar -->
|
|
<div class="help-sidebar">
|
|
<h5><i class="fas fa-info-circle"></i> Help & Guidelines</h5>
|
|
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">Shift Types</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul>
|
|
<li><strong>Morning:</strong> Typically 7:00 AM - 3:00 PM</li>
|
|
<li><strong>Afternoon:</strong> Typically 3:00 PM - 11:00 PM</li>
|
|
<li><strong>Night:</strong> Typically 11:00 PM - 7:00 AM</li>
|
|
<li><strong>Full Day:</strong> Typically 8:00 AM - 5:00 PM</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">Scheduling Tips</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul>
|
|
<li>Check for scheduling conflicts before saving</li>
|
|
<li>Consider employee preferences and skills</li>
|
|
<li>Be mindful of overtime regulations</li>
|
|
<li>Ensure adequate rest periods between shifts</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end col-4 -->
|
|
</div>
|
|
<!-- end row -->
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<!-- DateTimePicker JS -->
|
|
<script src="{% static 'plugins/bootstrap-datepicker/js/bootstrap-datepicker.min.js' %}"></script>
|
|
<script src="{% static 'plugins/bootstrap-timepicker/js/bootstrap-timepicker.min.js' %}"></script>
|
|
<!-- Select2 JS -->
|
|
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize Select2
|
|
$('#{{ form.schedule.id_for_label }}, #{{ form.employee.id_for_label }}, #{{ form.status.id_for_label }}').select2({
|
|
theme: 'bootstrap-5',
|
|
placeholder: "Select an option"
|
|
});
|
|
|
|
// Initialize DatePicker
|
|
$('#{{ form.date.id_for_label }}').datepicker({
|
|
format: 'yyyy-mm-dd',
|
|
autoclose: true,
|
|
todayHighlight: true
|
|
});
|
|
|
|
// Initialize TimePicker
|
|
$('#{{ form.start_time.id_for_label }}, #{{ form.end_time.id_for_label }}').timepicker({
|
|
showMeridian: false,
|
|
defaultTime: false
|
|
});
|
|
|
|
// Calculate hours based on start and end time
|
|
function calculateHours() {
|
|
var startTime = $('#{{ form.start_time.id_for_label }}').val();
|
|
var endTime = $('#{{ form.end_time.id_for_label }}').val();
|
|
|
|
if (startTime && endTime) {
|
|
// Parse times
|
|
var start = parseTime(startTime);
|
|
var end = parseTime(endTime);
|
|
|
|
// Calculate hours
|
|
var hours;
|
|
if (end < start) {
|
|
// Overnight shift
|
|
hours = (24 - start/60) + (end/60);
|
|
} else {
|
|
hours = (end - start) / 60;
|
|
}
|
|
|
|
$('#{{ form.hours.id_for_label }}').val(hours.toFixed(2));
|
|
}
|
|
}
|
|
|
|
// Parse time string to minutes
|
|
function parseTime(timeStr) {
|
|
var parts = timeStr.split(':');
|
|
return parseInt(parts[0]) * 60 + parseInt(parts[1]);
|
|
}
|
|
|
|
// Update hours when times change
|
|
$('#{{ form.start_time.id_for_label }}, #{{ form.end_time.id_for_label }}').change(function() {
|
|
calculateHours();
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|