bulk operations for dpi

This commit is contained in:
2026-05-26 20:11:55 +03:00
parent 70b712ff3b
commit f7e97f55e9
2 changed files with 271 additions and 0 deletions
+185
View File
@@ -260,6 +260,13 @@ $sql = "
$stmtEmployees = $pdo->query($sql);
$employees = $stmtEmployees->fetchAll(PDO::FETCH_ASSOC);
// Employees for the bulk-DPI multiselect (alphabetical, with department for the "whole department" shortcut)
$employeesForSelect = $pdo->query("
SELECT id, first_name, last_name, employee_code, department_id
FROM employees
ORDER BY last_name, first_name
")->fetchAll(PDO::FETCH_ASSOC);
// Job roles for the dropdown
$jobRoles = $pdo->query("
SELECT id, name FROM job_roles WHERE is_active = 1 ORDER BY sort_order, name
@@ -463,6 +470,9 @@ $allSkills = $stmtSkills->fetchAll(PDO::FETCH_ASSOC);
<button class="btn btn-matrix" onclick="location.href='skill_matrix.php'">
📊 Matrice Skills
</button>
<button type="button" class="btn btn-matrix" id="btnBulkPpe" data-bs-toggle="modal" data-bs-target="#bulkPpeModal">
🦺 Assegna DPI
</button>
<button class="btn btn-add" data-bs-toggle="modal" data-bs-target="#addEmployeeModal">
Aggiungi Dipendente
</button>
@@ -854,6 +864,75 @@ $allSkills = $stmtSkills->fetchAll(PDO::FETCH_ASSOC);
</div>
</div>
<!-- BULK DPI MODAL -->
<div class="modal fade" id="bulkPpeModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">🦺 Assegna DPI a più dipendenti</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Chiudi"></button>
</div>
<form id="bulkPpeForm">
<div class="modal-body" style="max-height:65vh; overflow-y:auto;">
<p class="text-muted small">Registra la consegna dello stesso DPI, con gli stessi dati, per più dipendenti contemporaneamente.</p>
<div class="row g-3">
<div class="col-12 col-md-6">
<label class="form-label fw-semibold">DPI <span class="text-danger">*</span></label>
<input type="text" id="bulkPpeItemName" class="form-control" maxlength="255" placeholder="es. Casco, Guanti, Scarpe antinfortunistiche" required>
</div>
<div class="col-6 col-md-3">
<label class="form-label fw-semibold">Data consegna</label>
<input type="date" id="bulkPpeDeliveryDate" class="form-control" value="<?= date('Y-m-d') ?>">
</div>
<div class="col-6 col-md-3">
<label class="form-label fw-semibold">Consegnato da</label>
<input type="text" id="bulkPpeDeliveredBy" class="form-control" maxlength="255" placeholder="Nome o azienda">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Note</label>
<textarea id="bulkPpeNotes" class="form-control" rows="2" placeholder="Opzionale"></textarea>
</div>
<div class="col-12">
<hr class="my-1">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Dipendenti <span class="text-danger">*</span></label>
<div class="d-flex flex-wrap gap-2 mb-2 align-items-end">
<div>
<select id="bulkPpeDept" class="form-select form-select-sm" style="min-width:180px">
<option value=""> Reparto </option>
<?php foreach ($departments as $d): ?>
<option value="<?= (int)$d['id'] ?>"><?= htmlspecialchars($d['name'], ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<button type="button" class="btn btn-sm btn-outline-primary" id="bulkPpeAddDept">+ Aggiungi reparto</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="bulkPpeSelectAll">Tutti</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="bulkPpeClear">Pulisci</button>
</div>
<select id="bulkPpeEmployees" class="form-select" multiple required>
<?php foreach ($employeesForSelect as $e): ?>
<option value="<?= (int)$e['id'] ?>" data-dept="<?= (int)($e['department_id'] ?? 0) ?>">
<?= htmlspecialchars(trim($e['last_name'] . ' ' . $e['first_name']), ENT_QUOTES, 'UTF-8') ?><?php if (!empty($e['employee_code'])): ?> (<?= htmlspecialchars($e['employee_code'], ENT_QUOTES, 'UTF-8') ?>)<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text"><span id="bulkPpeCount">0</span> dipendenti selezionati</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Annulla</button>
<button type="submit" class="btn btn-primary" id="bulkPpeSaveBtn">Assegna DPI</button>
</div>
</form>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
@@ -879,6 +958,112 @@ $allSkills = $stmtSkills->fetchAll(PDO::FETCH_ASSOC);
width: '100%'
});
/* -------- BULK DPI ASSIGN -------- */
var $bulkPpeEmp = $('#bulkPpeEmployees');
$bulkPpeEmp.select2({
theme: 'bootstrap-5',
placeholder: 'Seleziona dipendenti...',
dropdownParent: $('#bulkPpeModal'),
closeOnSelect: false,
width: '100%'
});
function bulkPpeUpdateCount() {
$('#bulkPpeCount').text(($bulkPpeEmp.val() || []).length);
}
$bulkPpeEmp.on('change', bulkPpeUpdateCount);
// Reset the form (and the save button) each time the modal opens
$('#btnBulkPpe').on('click', function() {
document.getElementById('bulkPpeForm').reset();
$bulkPpeEmp.val(null).trigger('change');
bulkPpeUpdateCount();
var sb = document.getElementById('bulkPpeSaveBtn');
sb.disabled = false;
sb.innerHTML = 'Assegna DPI';
});
// Add every employee of the chosen department to the selection
$('#bulkPpeAddDept').on('click', function() {
var dept = $('#bulkPpeDept').val();
if (!dept) return;
var current = ($bulkPpeEmp.val() || []).map(String);
$bulkPpeEmp.find('option').each(function() {
if (this.getAttribute('data-dept') === String(dept) && current.indexOf(this.value) === -1) {
current.push(this.value);
}
});
$bulkPpeEmp.val(current).trigger('change');
});
$('#bulkPpeSelectAll').on('click', function() {
var all = $bulkPpeEmp.find('option').map(function() {
return this.value;
}).get();
$bulkPpeEmp.val(all).trigger('change');
});
$('#bulkPpeClear').on('click', function() {
$bulkPpeEmp.val(null).trigger('change');
});
$('#bulkPpeForm').on('submit', function(e) {
e.preventDefault();
var itemName = $('#bulkPpeItemName').val().trim();
var emps = $bulkPpeEmp.val() || [];
if (!itemName) {
Swal.fire('Attenzione', 'Indicare il nome del DPI.', 'warning');
return;
}
if (emps.length === 0) {
Swal.fire('Attenzione', 'Selezionare almeno un dipendente.', 'warning');
return;
}
var btn = document.getElementById('bulkPpeSaveBtn');
btn.disabled = true;
var orig = btn.innerHTML;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Salvataggio...';
var fd = new FormData();
fd.append('item_name', itemName);
fd.append('delivery_date', $('#bulkPpeDeliveryDate').val());
fd.append('delivered_by', $('#bulkPpeDeliveredBy').val());
fd.append('notes', $('#bulkPpeNotes').val());
emps.forEach(function(id) {
fd.append('employee_ids[]', id);
});
fetch('ajax/employee_profile/save_bulk_ppe.php', {
method: 'POST',
body: fd
})
.then(function(r) {
return r.json();
})
.then(function(data) {
if (data.success) {
bootstrap.Modal.getInstance(document.getElementById('bulkPpeModal')).hide();
Swal.fire({
icon: 'success',
title: 'Fatto',
text: data.message,
timer: 2000,
showConfirmButton: false
});
} else {
btn.disabled = false;
btn.innerHTML = orig;
Swal.fire('Errore', data.message || 'Errore.', 'error');
}
})
.catch(function() {
btn.disabled = false;
btn.innerHTML = orig;
Swal.fire('Errore', 'Errore di connessione.', 'error');
});
});
function syncAddRoleVisibility() {
const authUserId = $('#addAuthUserId').val();