fixed worksheet modal

This commit is contained in:
2026-03-23 17:49:48 +01:00
parent d2f2a9089e
commit 2642906a9b
6 changed files with 1284 additions and 572 deletions
+462 -27
View File
@@ -7,9 +7,38 @@ include('include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
function h($v)
{
return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
}
function formatDateIT($d)
{
if (!$d || $d === '0000-00-00') return '—';
return date('d/m/Y', strtotime($d));
}
function formatDateTimeIT($d)
{
if (!$d || $d === '0000-00-00 00:00:00') return '—';
return date('d/m/Y H:i', strtotime($d));
}
function getRevisionLabel($rev)
{
$rev = trim((string)$rev);
return $rev !== '' ? $rev : '0';
}
function getWorksheetLabel($num)
{
$num = (int)$num;
return $num > 0 ? 'FL' . $num : '—';
}
// AJAX HANDLERS
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
header('Content-Type: application/json');
header('Content-Type: application/json; charset=utf-8');
$action = $_POST['action'] ?? '';
@@ -21,7 +50,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
exit;
}
// Delete header (rows will be deleted by FK cascade if constraints exist)
$stmt = $pdo->prepare("DELETE FROM work_sheets WHERE id = ?");
$stmt->execute([$id]);
@@ -29,9 +57,216 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
exit;
}
if ($action === 'create_revision') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'ID non valido']);
exit;
}
$stmt = $pdo->prepare("
SELECT *
FROM work_sheets
WHERE id = ?
LIMIT 1
");
$stmt->execute([$id]);
$source = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$source) {
echo json_encode(['success' => false, 'message' => 'Foglio non trovato']);
exit;
}
if (($source['worksheet_status'] ?? 'active') !== 'active') {
echo json_encode([
'success' => false,
'message' => 'Questo foglio è già inattivo/revisionato e non può essere revisionato di nuovo'
]);
exit;
}
$idmatrice = (int)$source['idmatrice'];
if ($idmatrice <= 0) {
echo json_encode(['success' => false, 'message' => 'ID matrice non valido']);
exit;
}
$worksheetNumber = (int)($source['worksheet_number'] ?? 0);
if ($worksheetNumber <= 0) {
echo json_encode(['success' => false, 'message' => 'Numero foglio non valido o non valorizzato']);
exit;
}
$pdo->beginTransaction();
// Trova la prossima revisione sulla stessa numerazione foglio
$stmtMaxRev = $pdo->prepare("
SELECT revision_code
FROM work_sheets
WHERE worksheet_number = ?
ORDER BY
CASE
WHEN revision_code IS NULL OR revision_code = '' THEN 0
WHEN revision_code REGEXP '^R[0-9]+$' THEN CAST(SUBSTRING(revision_code, 2) AS UNSIGNED)
ELSE 0
END DESC,
id DESC
LIMIT 1
");
$stmtMaxRev->execute([$worksheetNumber]);
$lastRevisionCode = $stmtMaxRev->fetchColumn();
$nextRevisionNumber = 1;
if ($lastRevisionCode && preg_match('/^R(\d+)$/', $lastRevisionCode, $m)) {
$nextRevisionNumber = ((int)$m[1]) + 1;
}
$newRevisionCode = 'R' . $nextRevisionNumber;
// Rendi inattivo il foglio corrente
$stmtDeactivate = $pdo->prepare("
UPDATE work_sheets
SET worksheet_status = 'inactive'
WHERE id = ?
");
$stmtDeactivate->execute([$id]);
// Crea clone del foglio mantenendo lo stesso worksheet_number
$stmtInsert = $pdo->prepare("
INSERT INTO work_sheets (
worksheet_number,
idmatrice,
worksheet_date,
customer_name,
profile_type_code,
revision_code,
worksheet_status,
marking,
prod_control_measure_settings,
control_frequency_cut,
control_frequency_drawing,
control_frequency_jig,
control_mode_jig,
requested_package_code,
meters_per_package,
meters_per_package_tolerance,
meters_per_package_notes,
box_type,
packages_or_pieces_per_box,
meters_per_box,
pallet_type,
boxes_or_packages_per_pallet,
speed_expected_kg_h,
speed_actual_kg_h,
speed_expected_m_h,
speed_actual_m_h,
approved_by,
notes
) VALUES (
?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?
)
");
$stmtInsert->execute([
$worksheetNumber,
$source['idmatrice'],
$source['worksheet_date'],
$source['customer_name'],
$source['profile_type_code'],
$newRevisionCode,
'active',
$source['marking'],
$source['prod_control_measure_settings'],
$source['control_frequency_cut'],
$source['control_frequency_drawing'],
$source['control_frequency_jig'],
$source['control_mode_jig'],
$source['requested_package_code'],
$source['meters_per_package'],
$source['meters_per_package_tolerance'],
$source['meters_per_package_notes'],
$source['box_type'],
$source['packages_or_pieces_per_box'],
$source['meters_per_box'],
$source['pallet_type'],
$source['boxes_or_packages_per_pallet'],
$source['speed_expected_kg_h'],
$source['speed_actual_kg_h'],
$source['speed_expected_m_h'],
$source['speed_actual_m_h'],
$source['approved_by'],
$source['notes']
]);
$newWorksheetId = (int)$pdo->lastInsertId();
// Duplica le mescole collegate
$stmtMixes = $pdo->prepare("
SELECT
idmescola,
mix_position,
mix_weight_g_m,
required_density,
required_hardness_shore_a,
lubrication_type,
lubrication_notes
FROM work_sheet_mescole
WHERE worksheet_id = ?
ORDER BY mix_position ASC, id ASC
");
$stmtMixes->execute([$id]);
$mixRows = $stmtMixes->fetchAll(PDO::FETCH_ASSOC);
if ($mixRows) {
$stmtInsertMix = $pdo->prepare("
INSERT INTO work_sheet_mescole (
worksheet_id,
idmescola,
mix_position,
mix_weight_g_m,
required_density,
required_hardness_shore_a,
lubrication_type,
lubrication_notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
");
foreach ($mixRows as $mix) {
$stmtInsertMix->execute([
$newWorksheetId,
$mix['idmescola'],
$mix['mix_position'],
$mix['mix_weight_g_m'],
$mix['required_density'],
$mix['required_hardness_shore_a'],
$mix['lubrication_type'],
$mix['lubrication_notes']
]);
}
}
$pdo->commit();
echo json_encode([
'success' => true,
'message' => 'Revisione creata correttamente',
'new_id' => $newWorksheetId,
'new_revision_code' => $newRevisionCode,
'worksheet_number_label' => 'FL' . $worksheetNumber
]);
exit;
}
echo json_encode(['success' => false, 'message' => 'Azione sconosciuta']);
exit;
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
exit;
}
@@ -41,17 +276,25 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
$worksheets = $pdo->query("
SELECT
ws.id,
ws.worksheet_number,
ws.worksheet_date,
ws.customer_name,
ws.profile_type_code,
ws.revision_code,
ws.worksheet_status,
ws.approved_by,
ws.created_at,
ws.updated_at,
m.nome AS matrice_nome,
m.cliente AS matrice_cliente,
(SELECT COUNT(*) FROM work_sheet_mescole wsm WHERE wsm.worksheet_id = ws.id) AS mixes_count
(
SELECT COUNT(*)
FROM work_sheet_mescole wsm
WHERE wsm.worksheet_id = ws.id
) AS mixes_count
FROM work_sheets ws
LEFT JOIN matrice m ON ws.idmatrice = m.id
ORDER BY ws.id DESC
ORDER BY ws.worksheet_number DESC, ws.id DESC
")->fetchAll(PDO::FETCH_ASSOC);
?>
@@ -74,10 +317,8 @@ $worksheets = $pdo->query("
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/@ttskch/select2-bootstrap4-theme@1.5.2/dist/select2-bootstrap4.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<style>
body {
font-size: 0.95rem;
@@ -106,15 +347,90 @@ $worksheets = $pdo->query("
font-weight: 500;
}
.btn-add:hover {
color: #fff;
}
.table thead {
background: #cfe3ff;
color: #1f2d3d;
}
.badge-revision {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 48px;
padding: 6px 10px;
border-radius: 999px;
background: #e7f1ff;
color: #0d6efd;
font-weight: 700;
font-size: 0.85rem;
}
.badge-fl {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 68px;
padding: 6px 12px;
border-radius: 999px;
background: #e8f7ee;
color: #198754;
font-weight: 800;
font-size: 0.86rem;
}
.badge-status-active {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 90px;
padding: 6px 10px;
border-radius: 999px;
background: #d1e7dd;
color: #0f5132;
font-weight: 700;
font-size: 0.85rem;
}
.badge-status-inactive {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 90px;
padding: 6px 10px;
border-radius: 999px;
background: #f8d7da;
color: #842029;
font-weight: 700;
font-size: 0.85rem;
}
.row-inactive {
opacity: 0.78;
background: #fcfcfd !important;
}
.btn-rev {
border-radius: 8px;
font-weight: 700;
}
.btn-rev[disabled] {
cursor: not-allowed;
opacity: 0.65;
}
.table td,
.table th {
vertical-align: middle;
}
/* Select2 Bootstrap sizing alignment */
.select2-container .select2-selection--single {
height: calc(2.375rem + 2px);
/* matches .form-select default height */
padding: 0.375rem 0.75rem;
border: 1px solid #ced4da;
border-radius: 0.375rem;
@@ -131,7 +447,6 @@ $worksheets = $pdo->query("
height: calc(2.375rem + 2px);
}
/* Make it full width */
.select2-container {
width: 100% !important;
}
@@ -158,14 +473,16 @@ $worksheets = $pdo->query("
</div>
<div class="table-responsive">
<table id="tabellaWorksheets" class="table table-striped table-bordered">
<table id="tabellaWorksheets" class="table table-striped table-bordered align-middle">
<thead>
<tr>
<th>ID</th>
<th>Foglio</th>
<th>Rev</th>
<th>Data</th>
<th>Matrice/Profilo</th>
<th>Cliente</th>
<th>Codice Profilo</th>
<th>Stato</th>
<th>Mescole</th>
<th>Visto</th>
<th>Creato</th>
@@ -174,24 +491,60 @@ $worksheets = $pdo->query("
</thead>
<tbody>
<?php foreach ($worksheets as $ws): ?>
<tr>
<td><?= (int)$ws['id'] ?></td>
<td><?= htmlspecialchars($ws['worksheet_date'] ?? '-') ?></td>
<td><?= htmlspecialchars($ws['matrice_nome'] ?? '-') ?></td>
<td><?= htmlspecialchars($ws['customer_name'] ?: ($ws['matrice_cliente'] ?? '-')) ?></td>
<td><?= htmlspecialchars($ws['profile_type_code'] ?? '-') ?></td>
<?php
$status = trim((string)($ws['worksheet_status'] ?? 'active'));
if ($status === '') $status = 'active';
$isActive = ($status === 'active');
$revisionLabel = getRevisionLabel($ws['revision_code'] ?? '');
$worksheetLabel = getWorksheetLabel($ws['worksheet_number'] ?? 0);
?>
<tr class="<?= !$isActive ? 'row-inactive' : '' ?>">
<td>
<span class="badge-fl"><?= h($worksheetLabel) ?></span>
</td>
<td>
<span class="badge-revision"><?= h($revisionLabel) ?></span>
</td>
<td><?= h(formatDateIT($ws['worksheet_date'] ?? '')) ?></td>
<td><?= h($ws['matrice_nome'] ?? '-') ?></td>
<td><?= h($ws['customer_name'] ?: ($ws['matrice_cliente'] ?? '-')) ?></td>
<td><?= h($ws['profile_type_code'] ?? '-') ?></td>
<td>
<?php if ($isActive): ?>
<span class="badge-status-active">Attivo</span>
<?php else: ?>
<span class="badge-status-inactive">Inattivo</span>
<?php endif; ?>
</td>
<td><?= (int)$ws['mixes_count'] ?></td>
<td><?= htmlspecialchars($ws['approved_by'] ?? '-') ?></td>
<td><?= htmlspecialchars($ws['created_at'] ?? '-') ?></td>
<td><?= h($ws['approved_by'] ?? '-') ?></td>
<td><?= h(formatDateTimeIT($ws['created_at'] ?? '')) ?></td>
<td class="text-nowrap">
<button class="btn btn-sm btn-outline-primary"
onclick="location.href='manage-worksheet.php?id=<?= (int)$ws['id'] ?>'">
✏️ Modifica
<?php if ($isActive): ?>
<button class="btn btn-sm btn-outline-primary"
onclick="location.href='manage-worksheet.php?id=<?= (int)$ws['id'] ?>'">
✏️ Modifica
</button>
<?php else: ?>
<button class="btn btn-sm btn-outline-secondary"
onclick="location.href='manage-worksheet.php?id=<?= (int)$ws['id'] ?>'">
👁️ Vedi
</button>
<?php endif; ?>
<button class="btn btn-sm btn-outline-info btn-rev create-revision"
data-id="<?= (int)$ws['id'] ?>"
data-name="<?= h(($ws['matrice_nome'] ?? 'Foglio') . ' ' . $worksheetLabel) ?>"
data-rev="<?= h($revisionLabel) ?>"
data-fl="<?= h($worksheetLabel) ?>"
<?= !$isActive ? 'disabled title="Foglio già revisionato/inattivo"' : '' ?>>
REV
</button>
<button class="btn btn-sm btn-outline-danger delete-ws"
data-id="<?= (int)$ws['id'] ?>"
data-name="<?= htmlspecialchars(($ws['matrice_nome'] ?? 'Foglio') . ' #' . $ws['id'], ENT_QUOTES) ?>">
data-name="<?= h(($ws['matrice_nome'] ?? 'Foglio') . ' ' . $worksheetLabel . ' rev. ' . $revisionLabel) ?>">
🗑️ Elimina
</button>
</td>
@@ -251,11 +604,10 @@ $worksheets = $pdo->query("
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Eliminato!',
timer: 900
})
.then(() => location.reload());
icon: 'success',
title: 'Eliminato!',
timer: 900
}).then(() => location.reload());
} else {
Swal.fire({
icon: 'error',
@@ -266,6 +618,89 @@ $worksheets = $pdo->query("
});
});
});
$(document).on('click', '.create-revision', function() {
if ($(this).is(':disabled')) {
return;
}
const id = $(this).data('id');
const name = $(this).data('name');
const rev = $(this).data('rev');
const fl = $(this).data('fl');
Swal.fire({
title: 'Creare una nuova revisione?',
html: `
<div class="text-start">
<div><strong>Foglio:</strong> ${fl}</div>
<div><strong>Profilo:</strong> ${name}</div>
<div><strong>Revisione attuale:</strong> ${rev}</div>
<hr>
<div>Il sistema:</div>
<ul style="text-align:left; margin-top:8px;">
<li>renderà inattivo il foglio corrente</li>
<li>creerà un clone completo</li>
<li>duplicherà anche le mescole</li>
<li>manterrà lo stesso numero foglio</li>
<li>assegnerà la nuova revisione progressiva</li>
</ul>
</div>
`,
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#0dcaf0',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Sì, crea revisione',
cancelButtonText: 'Annulla'
}).then(result => {
if (!result.isConfirmed) return;
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `ajax=1&action=create_revision&id=${id}`
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Revisione creata',
html: `
<div>Foglio: <strong>${data.worksheet_number_label}</strong></div>
<div class="mt-1">Nuova revisione: <strong>${data.new_revision_code}</strong></div>
<div class="mt-2">Vuoi aprire subito il nuovo foglio?</div>
`,
showCancelButton: true,
confirmButtonText: 'Apri nuovo foglio',
cancelButtonText: 'Resta qui'
}).then(res => {
if (res.isConfirmed) {
window.location.href = 'manage-worksheet.php?id=' + data.new_id;
} else {
location.reload();
}
});
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
}
})
.catch(() => {
Swal.fire({
icon: 'error',
title: 'Errore',
text: 'Errore durante la creazione della revisione'
});
});
});
});
});
</script>
</body>