Ver 6
This commit is contained in:
parent
6cb2211e8f
commit
c6cc41cce3
Binary file not shown.
@ -15,7 +15,7 @@
|
|||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
<div class="card p-4 shadow-sm">
|
<div class="card p-4 shadow-sm">
|
||||||
<form method="post">
|
<form method="post" id="workLogForm">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
@ -79,6 +79,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if is_conflict %}
|
||||||
|
<!-- Conflict Resolution Modal -->
|
||||||
|
<div class="modal fade" id="conflictModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="conflictModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-warning text-dark">
|
||||||
|
<h5 class="modal-title fw-bold" id="conflictModalLabel">
|
||||||
|
Duplicate Logs Detected
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p class="fw-bold">The following workers have already been logged for {{ conflict_date }}:</p>
|
||||||
|
<div class="card bg-light mb-3">
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
{% for worker in conflicting_workers %}
|
||||||
|
<li class="list-group-item bg-transparent">{{ worker.name }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<p>How would you like to proceed?</p>
|
||||||
|
<div class="alert alert-info small mb-0">
|
||||||
|
<strong>Skip:</strong> Log only the new workers. Keep existing logs as they are.<br>
|
||||||
|
<strong>Overwrite:</strong> Remove these workers from previous logs for this date and add them here.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" onclick="submitConflict('skip')">Skip Duplicate Workers</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="submitConflict('overwrite')">Overwrite Existing</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.hover-shadow:hover {
|
.hover-shadow:hover {
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
@ -105,7 +139,6 @@
|
|||||||
// Select workers belonging to the team
|
// Select workers belonging to the team
|
||||||
workerIds.forEach(function(id) {
|
workerIds.forEach(function(id) {
|
||||||
// Find the checkbox for this worker ID
|
// Find the checkbox for this worker ID
|
||||||
// Django form checkboxes usually have name 'workers' and value equal to ID
|
|
||||||
const checkbox = document.querySelector(`input[name="workers"][value="${id}"]`);
|
const checkbox = document.querySelector(`input[name="workers"][value="${id}"]`);
|
||||||
if (checkbox) {
|
if (checkbox) {
|
||||||
checkbox.checked = true;
|
checkbox.checked = true;
|
||||||
@ -114,6 +147,27 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show conflict modal if it exists
|
||||||
|
const conflictModalEl = document.getElementById('conflictModal');
|
||||||
|
if (conflictModalEl) {
|
||||||
|
var myModal = new bootstrap.Modal(conflictModalEl);
|
||||||
|
myModal.show();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function submitConflict(action) {
|
||||||
|
const form = document.getElementById('workLogForm');
|
||||||
|
// Check if input already exists
|
||||||
|
let input = form.querySelector('input[name="conflict_action"]');
|
||||||
|
if (!input) {
|
||||||
|
input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = 'conflict_action';
|
||||||
|
form.appendChild(input);
|
||||||
|
}
|
||||||
|
input.value = action;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -62,19 +62,7 @@ def home(request):
|
|||||||
return render(request, "core/index.html", context)
|
return render(request, "core/index.html", context)
|
||||||
|
|
||||||
def log_attendance(request):
|
def log_attendance(request):
|
||||||
if request.method == 'POST':
|
# Build team workers map for frontend JS (needed for both GET and POST if re-rendering)
|
||||||
form = WorkLogForm(request.POST, user=request.user)
|
|
||||||
if form.is_valid():
|
|
||||||
work_log = form.save(commit=False)
|
|
||||||
if request.user.is_authenticated:
|
|
||||||
work_log.supervisor = request.user
|
|
||||||
work_log.save()
|
|
||||||
form.save_m2m()
|
|
||||||
return redirect('home')
|
|
||||||
else:
|
|
||||||
form = WorkLogForm(user=request.user if request.user.is_authenticated else None)
|
|
||||||
|
|
||||||
# Build team workers map for frontend JS
|
|
||||||
teams_qs = Team.objects.filter(is_active=True)
|
teams_qs = Team.objects.filter(is_active=True)
|
||||||
if request.user.is_authenticated and not request.user.is_superuser:
|
if request.user.is_authenticated and not request.user.is_superuser:
|
||||||
teams_qs = teams_qs.filter(supervisor=request.user)
|
teams_qs = teams_qs.filter(supervisor=request.user)
|
||||||
@ -84,6 +72,72 @@ def log_attendance(request):
|
|||||||
# Get active workers for the team
|
# Get active workers for the team
|
||||||
active_workers = team.workers.filter(is_active=True).values_list('id', flat=True)
|
active_workers = team.workers.filter(is_active=True).values_list('id', flat=True)
|
||||||
team_workers_map[team.id] = list(active_workers)
|
team_workers_map[team.id] = list(active_workers)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = WorkLogForm(request.POST, user=request.user)
|
||||||
|
if form.is_valid():
|
||||||
|
date = form.cleaned_data['date']
|
||||||
|
selected_workers = form.cleaned_data['workers']
|
||||||
|
conflict_action = request.POST.get('conflict_action')
|
||||||
|
|
||||||
|
# Check for existing logs for these workers on this date
|
||||||
|
# We want to find workers who ARE in selected_workers AND have a WorkLog on 'date'
|
||||||
|
conflicting_workers = Worker.objects.filter(
|
||||||
|
work_logs__date=date,
|
||||||
|
id__in=selected_workers.values_list('id', flat=True)
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
if conflicting_workers.exists() and not conflict_action:
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'team_workers_json': json.dumps(team_workers_map),
|
||||||
|
'conflicting_workers': conflicting_workers,
|
||||||
|
'is_conflict': True,
|
||||||
|
'conflict_date': date,
|
||||||
|
}
|
||||||
|
return render(request, 'core/log_attendance.html', context)
|
||||||
|
|
||||||
|
# If we are here, either no conflicts or action is chosen
|
||||||
|
workers_to_save = list(selected_workers)
|
||||||
|
|
||||||
|
if conflict_action == 'skip':
|
||||||
|
# Exclude conflicting workers
|
||||||
|
conflicting_ids = conflicting_workers.values_list('id', flat=True)
|
||||||
|
workers_to_save = [w for w in selected_workers if w.id not in conflicting_ids]
|
||||||
|
|
||||||
|
if not workers_to_save:
|
||||||
|
messages.warning(request, "No new workers to log (all skipped).")
|
||||||
|
return redirect('home')
|
||||||
|
|
||||||
|
messages.success(request, f"Logged {len(workers_to_save)} workers (skipped {conflicting_workers.count()} duplicates).")
|
||||||
|
|
||||||
|
elif conflict_action == 'overwrite':
|
||||||
|
# Remove conflicting workers from their OLD logs
|
||||||
|
for worker in conflicting_workers:
|
||||||
|
old_logs = WorkLog.objects.filter(date=date, workers=worker)
|
||||||
|
for log in old_logs:
|
||||||
|
log.workers.remove(worker)
|
||||||
|
# Cleanup empty logs
|
||||||
|
if log.workers.count() == 0:
|
||||||
|
log.delete()
|
||||||
|
messages.success(request, f"Logged {len(workers_to_save)} workers (overwrote {conflicting_workers.count()} previous entries).")
|
||||||
|
|
||||||
|
else:
|
||||||
|
# No conflicts initially
|
||||||
|
messages.success(request, "Work log saved successfully.")
|
||||||
|
|
||||||
|
# Save the new log
|
||||||
|
work_log = form.save(commit=False)
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
work_log.supervisor = request.user
|
||||||
|
work_log.save()
|
||||||
|
|
||||||
|
# Manually set workers
|
||||||
|
work_log.workers.set(workers_to_save)
|
||||||
|
|
||||||
|
return redirect('home')
|
||||||
|
else:
|
||||||
|
form = WorkLogForm(user=request.user if request.user.is_authenticated else None)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'form': form,
|
'form': form,
|
||||||
@ -240,4 +294,4 @@ def payslip_detail(request, pk):
|
|||||||
'record': record,
|
'record': record,
|
||||||
'logs': logs,
|
'logs': logs,
|
||||||
}
|
}
|
||||||
return render(request, 'core/payslip.html', context)
|
return render(request, 'core/payslip.html', context)
|
||||||
Loading…
x
Reference in New Issue
Block a user