fixed worksheet modal
This commit is contained in:
parent
d2f2a9089e
commit
2642906a9b
254
public/userarea/ajax/worksheet-linked-data.php
Normal file
254
public/userarea/ajax/worksheet-linked-data.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
ob_start();
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require_once(__DIR__ . '/../../../extra/auth.php');
|
||||
require_once(__DIR__ . '/../class/db-functions.php');
|
||||
|
||||
while (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if (!class_exists('Auth')) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Classe Auth non disponibile'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!Auth::check()) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Sessione non valida o utente non autenticato'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$db = DBHandlerSelect::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
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 worksheetNumberLabel($n)
|
||||
{
|
||||
$n = (int)$n;
|
||||
return $n > 0 ? 'FL' . $n : '—';
|
||||
}
|
||||
|
||||
function revisionLabel($rev)
|
||||
{
|
||||
$rev = trim((string)$rev);
|
||||
return $rev !== '' ? $rev : '0';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
try {
|
||||
if ($action === 'get_matrice_worksheets') {
|
||||
$idmatrice = isset($_POST['idmatrice']) ? (int)$_POST['idmatrice'] : 0;
|
||||
if ($idmatrice <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'ID matrice non valido'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ws.id,
|
||||
ws.idmatrice,
|
||||
ws.worksheet_number,
|
||||
ws.revision_code,
|
||||
ws.worksheet_status,
|
||||
ws.worksheet_date,
|
||||
ws.customer_name,
|
||||
ws.profile_type_code,
|
||||
ws.marking,
|
||||
ws.approved_by,
|
||||
ws.created_at,
|
||||
ws.updated_at,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM work_sheet_mescole wsm
|
||||
WHERE wsm.worksheet_id = ws.id
|
||||
) AS mix_count
|
||||
FROM work_sheets ws
|
||||
WHERE ws.idmatrice = ?
|
||||
ORDER BY
|
||||
ws.worksheet_number DESC,
|
||||
CASE
|
||||
WHEN ws.revision_code IS NULL OR ws.revision_code = '' THEN 0
|
||||
WHEN ws.revision_code REGEXP '^R[0-9]+$' THEN CAST(SUBSTRING(ws.revision_code, 2) AS UNSIGNED)
|
||||
ELSE 0
|
||||
END DESC,
|
||||
ws.id DESC
|
||||
");
|
||||
$stmt->execute([$idmatrice]);
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$data = [];
|
||||
foreach ($rows as $r) {
|
||||
$data[] = [
|
||||
'id' => (int)$r['id'],
|
||||
'idmatrice' => (int)$r['idmatrice'],
|
||||
'worksheet_number' => (int)($r['worksheet_number'] ?? 0),
|
||||
'worksheet_number_label' => worksheetNumberLabel($r['worksheet_number'] ?? 0),
|
||||
'revision_code' => $r['revision_code'] ?? '',
|
||||
'revision_label' => revisionLabel($r['revision_code'] ?? ''),
|
||||
'worksheet_status' => $r['worksheet_status'] ?? 'active',
|
||||
'worksheet_status_label' => (($r['worksheet_status'] ?? 'active') === 'inactive') ? 'Inattivo' : 'Attivo',
|
||||
'worksheet_date' => $r['worksheet_date'],
|
||||
'worksheet_date_it' => formatDateIT($r['worksheet_date']),
|
||||
'customer_name' => $r['customer_name'] ?? '',
|
||||
'profile_type_code' => $r['profile_type_code'] ?? '',
|
||||
'marking' => $r['marking'] ?? '',
|
||||
'approved_by' => $r['approved_by'] ?? '',
|
||||
'created_at' => $r['created_at'] ?? '',
|
||||
'created_at_it' => formatDateTimeIT($r['created_at'] ?? ''),
|
||||
'updated_at' => $r['updated_at'] ?? '',
|
||||
'updated_at_it' => formatDateTimeIT($r['updated_at'] ?? ''),
|
||||
'mix_count' => (int)($r['mix_count'] ?? 0)
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'worksheets' => $data
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'get_worksheet_detail') {
|
||||
$worksheetId = isset($_POST['worksheet_id']) ? (int)$_POST['worksheet_id'] : 0;
|
||||
if ($worksheetId <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'ID foglio non valido'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ws.*,
|
||||
m.nome AS matrice_nome,
|
||||
m.cliente AS matrice_cliente
|
||||
FROM work_sheets ws
|
||||
LEFT JOIN matrice m ON m.id = ws.idmatrice
|
||||
WHERE ws.id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$worksheetId]);
|
||||
$ws = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$ws) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Foglio di lavoro non trovato'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmtMix = $pdo->prepare("
|
||||
SELECT
|
||||
wsm.*,
|
||||
me.nome AS mescola_nome,
|
||||
me.nomeuscita AS mescola_uscita
|
||||
FROM work_sheet_mescole wsm
|
||||
LEFT JOIN mescole me ON me.id = wsm.idmescola
|
||||
WHERE wsm.worksheet_id = ?
|
||||
ORDER BY wsm.mix_position ASC, wsm.id ASC
|
||||
");
|
||||
$stmtMix->execute([$worksheetId]);
|
||||
$mixRows = $stmtMix->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'worksheet' => [
|
||||
'id' => (int)$ws['id'],
|
||||
'worksheet_number' => (int)($ws['worksheet_number'] ?? 0),
|
||||
'worksheet_number_label' => worksheetNumberLabel($ws['worksheet_number'] ?? 0),
|
||||
'revision_code' => $ws['revision_code'] ?? '',
|
||||
'revision_label' => revisionLabel($ws['revision_code'] ?? ''),
|
||||
'worksheet_status' => $ws['worksheet_status'] ?? 'active',
|
||||
'worksheet_status_label' => (($ws['worksheet_status'] ?? 'active') === 'inactive') ? 'Inattivo' : 'Attivo',
|
||||
'idmatrice' => (int)$ws['idmatrice'],
|
||||
'matrice_nome' => $ws['matrice_nome'] ?? '',
|
||||
'matrice_cliente' => $ws['matrice_cliente'] ?? '',
|
||||
'worksheet_date' => $ws['worksheet_date'] ?? '',
|
||||
'worksheet_date_it' => formatDateIT($ws['worksheet_date'] ?? ''),
|
||||
'customer_name' => $ws['customer_name'] ?? '',
|
||||
'profile_type_code' => $ws['profile_type_code'] ?? '',
|
||||
'marking' => $ws['marking'] ?? '',
|
||||
'prod_control_measure_settings' => $ws['prod_control_measure_settings'] ?? '',
|
||||
'control_frequency_cut' => $ws['control_frequency_cut'] ?? '',
|
||||
'control_frequency_drawing' => $ws['control_frequency_drawing'] ?? '',
|
||||
'control_frequency_jig' => $ws['control_frequency_jig'] ?? '',
|
||||
'control_mode_jig' => $ws['control_mode_jig'] ?? '',
|
||||
'requested_package_code' => $ws['requested_package_code'] ?? '',
|
||||
'meters_per_package' => $ws['meters_per_package'] ?? '',
|
||||
'meters_per_package_tolerance' => $ws['meters_per_package_tolerance'] ?? '',
|
||||
'meters_per_package_notes' => $ws['meters_per_package_notes'] ?? '',
|
||||
'box_type' => $ws['box_type'] ?? '',
|
||||
'packages_or_pieces_per_box' => $ws['packages_or_pieces_per_box'] ?? '',
|
||||
'meters_per_box' => $ws['meters_per_box'] ?? '',
|
||||
'pallet_type' => $ws['pallet_type'] ?? '',
|
||||
'boxes_or_packages_per_pallet' => $ws['boxes_or_packages_per_pallet'] ?? '',
|
||||
'speed_expected_kg_h' => $ws['speed_expected_kg_h'] ?? '',
|
||||
'speed_actual_kg_h' => $ws['speed_actual_kg_h'] ?? '',
|
||||
'speed_expected_m_h' => $ws['speed_expected_m_h'] ?? '',
|
||||
'speed_actual_m_h' => $ws['speed_actual_m_h'] ?? '',
|
||||
'approved_by' => $ws['approved_by'] ?? '',
|
||||
'notes' => $ws['notes'] ?? '',
|
||||
'created_at' => $ws['created_at'] ?? '',
|
||||
'created_at_it' => formatDateTimeIT($ws['created_at'] ?? ''),
|
||||
'updated_at' => $ws['updated_at'] ?? '',
|
||||
'updated_at_it' => formatDateTimeIT($ws['updated_at'] ?? '')
|
||||
],
|
||||
'mix_rows' => array_map(function ($r) {
|
||||
return [
|
||||
'id' => (int)$r['id'],
|
||||
'mix_position' => (int)$r['mix_position'],
|
||||
'mescola_nome' => $r['mescola_nome'] ?? '',
|
||||
'mescola_uscita' => $r['mescola_uscita'] ?? '',
|
||||
'mix_weight_g_m' => $r['mix_weight_g_m'] ?? '',
|
||||
'required_density' => $r['required_density'] ?? '',
|
||||
'required_hardness_shore_a' => $r['required_hardness_shore_a'] ?? '',
|
||||
'lubrication_type' => $r['lubrication_type'] ?? '',
|
||||
'lubrication_notes' => $r['lubrication_notes'] ?? ''
|
||||
];
|
||||
}, $mixRows)
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Azione AJAX sconosciuta'
|
||||
]);
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
362
public/userarea/assets/js/worksheets-linked-modals.js
Normal file
362
public/userarea/assets/js/worksheets-linked-modals.js
Normal file
@ -0,0 +1,362 @@
|
||||
(function () {
|
||||
function escapeHtml(str) {
|
||||
return String(str || "")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function valueOrDash(v) {
|
||||
return v === null || v === undefined || String(v).trim() === ""
|
||||
? "—"
|
||||
: escapeHtml(v);
|
||||
}
|
||||
|
||||
function renderReadonlyField(label, value) {
|
||||
return `
|
||||
<div class="readonly-label">${escapeHtml(label)}</div>
|
||||
<div class="readonly-value">${valueOrDash(value)}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
window.loadMatriceWorksheets = function (idmatrice, matriceNome, endpoint) {
|
||||
endpoint = endpoint || "ajax/worksheet-linked-data.php";
|
||||
|
||||
$("#wl_idmatrice").val(idmatrice);
|
||||
$("#wl_matrice_name").html(
|
||||
`<span class="worksheet-chip"><i class="fa-solid fa-layer-group"></i>${escapeHtml(matriceNome || "")}</span>`,
|
||||
);
|
||||
$("#worksheetsListContainer").html(
|
||||
'<div class="text-muted">Caricamento fogli di lavoro...</div>',
|
||||
);
|
||||
|
||||
fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body:
|
||||
"action=get_matrice_worksheets&idmatrice=" +
|
||||
encodeURIComponent(idmatrice),
|
||||
})
|
||||
.then(async (r) => {
|
||||
const text = await r.text();
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error("Risposta non JSON worksheets:", text);
|
||||
throw new Error("Risposta non JSON, vedi console");
|
||||
}
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data.success) {
|
||||
$("#worksheetsListContainer").html(
|
||||
'<div class="text-danger">Errore nel caricamento dei fogli</div>',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const rows = data.worksheets || [];
|
||||
|
||||
if (!rows.length) {
|
||||
$("#worksheetsListContainer").html(
|
||||
'<div class="text-muted">Nessun foglio di lavoro collegato a questo profilo</div>',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped align-middle worksheet-list-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:110px;">Foglio</th>
|
||||
<th style="width:100px;">Rev.</th>
|
||||
<th style="width:110px;">Stato</th>
|
||||
<th style="width:140px;">Data foglio</th>
|
||||
<th>Cliente</th>
|
||||
<th>Codice profilo</th>
|
||||
<th style="width:110px;">Mescole</th>
|
||||
<th style="width:230px;">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
rows.forEach((r) => {
|
||||
const statusBadge =
|
||||
r.worksheet_status === "inactive"
|
||||
? `<span class="worksheet-badge-status-inactive">Inattivo</span>`
|
||||
: `<span class="worksheet-badge-status-active">Attivo</span>`;
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td><span class="worksheet-badge-fl">${escapeHtml(r.worksheet_number_label || "—")}</span></td>
|
||||
<td><span class="worksheet-badge-rev">${escapeHtml(r.revision_label || "0")}</span></td>
|
||||
<td>${statusBadge}</td>
|
||||
<td>${escapeHtml(r.worksheet_date_it || "—")}</td>
|
||||
<td title="${escapeHtml(r.customer_name || "")}">${escapeHtml(r.customer_name || "—")}</td>
|
||||
<td>${escapeHtml(r.profile_type_code || "—")}</td>
|
||||
<td>${escapeHtml(String(r.mix_count || 0))}</td>
|
||||
<td class="text-nowrap">
|
||||
<button type="button"
|
||||
class="btn btn-view-worksheet open-worksheet-detail"
|
||||
data-id="${r.id}"
|
||||
data-endpoint="${escapeHtml(endpoint)}">
|
||||
<i class="fa-solid fa-eye me-1"></i>Apri dettaglio
|
||||
</button>
|
||||
<a class="worksheet-open-link ms-1"
|
||||
href="manage-worksheet.php?id=${r.id}"
|
||||
target="_blank">
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i>Apri pagina
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$("#worksheetsListContainer").html(html);
|
||||
})
|
||||
.catch(() => {
|
||||
$("#worksheetsListContainer").html(
|
||||
'<div class="text-danger">Errore nel caricamento dei fogli</div>',
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
window.loadWorksheetDetail = function (worksheetId, endpoint) {
|
||||
endpoint = endpoint || "ajax/worksheet-linked-data.php";
|
||||
|
||||
$("#worksheetDetailContainer").html(
|
||||
'<div class="text-muted">Caricamento dettaglio foglio...</div>',
|
||||
);
|
||||
|
||||
fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body:
|
||||
"action=get_worksheet_detail&worksheet_id=" +
|
||||
encodeURIComponent(worksheetId),
|
||||
})
|
||||
.then(async (r) => {
|
||||
const text = await r.text();
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error("Risposta non JSON worksheet detail:", text);
|
||||
throw new Error("Risposta non JSON, vedi console");
|
||||
}
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data.success) {
|
||||
console.error("Errore worksheets:", data);
|
||||
|
||||
$("#worksheetsListContainer").html(
|
||||
'<div class="text-danger">Errore nel caricamento dei fogli: ' +
|
||||
escapeHtml(
|
||||
data.message || "nessun dettaglio restituito",
|
||||
) +
|
||||
"</div>",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const ws = data.worksheet || {};
|
||||
const mixRows = data.mix_rows || [];
|
||||
|
||||
let mixHtml = `<div class="text-muted">Nessuna mescola associata</div>`;
|
||||
|
||||
if (mixRows.length) {
|
||||
mixHtml = `
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped align-middle mix-readonly-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:80px;">Pos</th>
|
||||
<th>Mescola</th>
|
||||
<th style="width:120px;">Peso g/m</th>
|
||||
<th style="width:140px;">Densità</th>
|
||||
<th style="width:150px;">Durezza</th>
|
||||
<th style="width:130px;">Lubr.</th>
|
||||
<th>Note lubr.</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
mixRows.forEach((r) => {
|
||||
const nomeMescola = r.mescola_uscita
|
||||
? `${escapeHtml(r.mescola_nome || "—")} <div class="small text-muted">${escapeHtml(r.mescola_uscita)}</div>`
|
||||
: escapeHtml(r.mescola_nome || "—");
|
||||
|
||||
mixHtml += `
|
||||
<tr>
|
||||
<td>${escapeHtml(String(r.mix_position || ""))}</td>
|
||||
<td>${nomeMescola}</td>
|
||||
<td>${valueOrDash(r.mix_weight_g_m)}</td>
|
||||
<td>${valueOrDash(r.required_density)}</td>
|
||||
<td>${valueOrDash(r.required_hardness_shore_a)}</td>
|
||||
<td>${valueOrDash(r.lubrication_type)}</td>
|
||||
<td>${valueOrDash(r.lubrication_notes)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
mixHtml += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const html = `
|
||||
<div class="worksheet-title-box mb-4">
|
||||
<div class="d-flex justify-content-between align-items-start gap-3 flex-wrap">
|
||||
<div>
|
||||
<h4 class="mb-1">${escapeHtml(ws.worksheet_number_label || "—")} / Rev. ${escapeHtml(ws.revision_label || "0")}</h4>
|
||||
<small>
|
||||
Stato: ${escapeHtml(ws.worksheet_status_label || "Attivo")}
|
||||
${ws.matrice_nome ? " • Profilo: " + escapeHtml(ws.matrice_nome) : ""}
|
||||
${ws.matrice_cliente ? " • Cliente matrice: " + escapeHtml(ws.matrice_cliente) : ""}
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage-worksheet.php?id=${escapeHtml(String(ws.id || ""))}"
|
||||
target="_blank"
|
||||
class="worksheet-open-link">
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i>
|
||||
Apri foglio completo
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Dati principali</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField("Foglio", ws.worksheet_number_label)}
|
||||
${renderReadonlyField("Revisione", ws.revision_label)}
|
||||
${renderReadonlyField("Stato", ws.worksheet_status_label)}
|
||||
${renderReadonlyField("Data foglio", ws.worksheet_date_it)}
|
||||
${renderReadonlyField("Cliente override", ws.customer_name)}
|
||||
${renderReadonlyField("Codice profilo", ws.profile_type_code)}
|
||||
${renderReadonlyField("Marchiatura", ws.marking)}
|
||||
${renderReadonlyField("Approvato da", ws.approved_by)}
|
||||
${renderReadonlyField("Creato il", ws.created_at_it)}
|
||||
${renderReadonlyField("Ultimo aggiornamento", ws.updated_at_it)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Controlli produzione</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField("Taglio", ws.control_frequency_cut)}
|
||||
${renderReadonlyField("Disegno", ws.control_frequency_drawing)}
|
||||
${renderReadonlyField("Dima", ws.control_frequency_jig)}
|
||||
${renderReadonlyField("Modalità dima", ws.control_mode_jig)}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="readonly-label mb-2">Impostazione misure controllo produzione</div>
|
||||
<div class="readonly-value" style="white-space:pre-wrap;">${valueOrDash(ws.prod_control_measure_settings)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Packaging / Confezionamento</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField("Codice confezione", ws.requested_package_code)}
|
||||
${renderReadonlyField("Metri per confezione", ws.meters_per_package)}
|
||||
${renderReadonlyField("Tolleranza metri/conf.", ws.meters_per_package_tolerance)}
|
||||
${renderReadonlyField("Scatola tipo", ws.box_type)}
|
||||
${renderReadonlyField("Conf./pezzi per scatola", ws.packages_or_pieces_per_box)}
|
||||
${renderReadonlyField("Metri per scatola", ws.meters_per_box)}
|
||||
${renderReadonlyField("Bancale tipo", ws.pallet_type)}
|
||||
${renderReadonlyField("Scatole/conf. per bancale", ws.boxes_or_packages_per_pallet)}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="readonly-label mb-2">Note metri / confezione</div>
|
||||
<div class="readonly-value" style="white-space:pre-wrap;">${valueOrDash(ws.meters_per_package_notes)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Velocità e note</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField("Vel. prevista kg/h", ws.speed_expected_kg_h)}
|
||||
${renderReadonlyField("Vel. effettiva kg/h", ws.speed_actual_kg_h)}
|
||||
${renderReadonlyField("Vel. prevista m/h", ws.speed_expected_m_h)}
|
||||
${renderReadonlyField("Vel. effettiva m/h", ws.speed_actual_m_h)}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="readonly-label mb-2">Note</div>
|
||||
<div class="readonly-value" style="white-space:pre-wrap;">${valueOrDash(ws.notes)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Mescole associate al foglio</div>
|
||||
<div class="readonly-card-body">
|
||||
${mixHtml}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$("#worksheetDetailContainer").html(html);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Catch loadMatriceWorksheets:", err);
|
||||
|
||||
$("#worksheetsListContainer").html(
|
||||
'<div class="text-danger">Errore nel caricamento dei fogli: ' +
|
||||
escapeHtml(err.message || "errore JavaScript/fetch") +
|
||||
"</div>",
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
$(document).on("click", ".worksheets, .show-worksheets", function () {
|
||||
const idmatrice = $(this).data("id");
|
||||
const nome = $(this).data("nome") || "";
|
||||
const endpoint =
|
||||
$(this).data("endpoint") || "ajax/worksheet-linked-data.php";
|
||||
|
||||
loadMatriceWorksheets(idmatrice, nome, endpoint);
|
||||
new bootstrap.Modal(
|
||||
document.getElementById("worksheetsListModal"),
|
||||
).show();
|
||||
});
|
||||
|
||||
$(document).on("click", ".open-worksheet-detail", function () {
|
||||
const worksheetId = $(this).data("id");
|
||||
const endpoint =
|
||||
$(this).data("endpoint") || "ajax/worksheet-linked-data.php";
|
||||
|
||||
loadWorksheetDetail(worksheetId, endpoint);
|
||||
new bootstrap.Modal(
|
||||
document.getElementById("worksheetDetailModal"),
|
||||
).show();
|
||||
});
|
||||
})();
|
||||
46
public/userarea/include/worksheets-linked-modals.php
Normal file
46
public/userarea/include/worksheets-linked-modals.php
Normal file
@ -0,0 +1,46 @@
|
||||
<!-- MODALE LISTA FOGLI DI LAVORO -->
|
||||
<div class="modal fade" id="worksheetsListModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-worksheet-list">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="background:linear-gradient(135deg,#e7f1ff,#d6e9ff);">
|
||||
<div>
|
||||
<h5 class="modal-title mb-0">
|
||||
<i class="fa-solid fa-clipboard-list me-2"></i>Fogli di lavoro collegati
|
||||
</h5>
|
||||
<small class="text-muted">Elenco fogli associati al profilo selezionato</small>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="wl_idmatrice">
|
||||
<div class="fw-semibold mb-3" id="wl_matrice_name" style="color:#0b3d91;"></div>
|
||||
|
||||
<div id="worksheetsListContainer">
|
||||
<div class="text-muted">Caricamento fogli di lavoro...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODALE DETTAGLIO FOGLIO DI LAVORO -->
|
||||
<div class="modal fade" id="worksheetDetailModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-worksheet-view">
|
||||
<div class="modal-content" style="min-height:92vh;">
|
||||
<div class="modal-header" style="background:linear-gradient(135deg,#e7f1ff,#d6e9ff);">
|
||||
<div>
|
||||
<h5 class="modal-title mb-0">
|
||||
<i class="fa-solid fa-file-lines me-2"></i>Dettaglio foglio di lavoro
|
||||
</h5>
|
||||
<small class="text-muted">Visualizzazione completa in sola lettura</small>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body" id="worksheetDetailContainer">
|
||||
<div class="text-muted">Caricamento dettaglio foglio...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -64,6 +64,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
|
||||
$approved_by = trim($_POST['approved_by'] ?? '');
|
||||
$notes = trim($_POST['notes'] ?? '');
|
||||
$worksheet_number = null;
|
||||
|
||||
if ($id > 0) {
|
||||
$stmt = $pdo->prepare("
|
||||
@ -128,34 +129,65 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$stmtNum = $pdo->query("
|
||||
SELECT IFNULL(MAX(worksheet_number), 0) + 1 AS next_number
|
||||
FROM work_sheets
|
||||
");
|
||||
$worksheet_number = (int)$stmtNum->fetchColumn();
|
||||
if ($worksheet_number <= 0) {
|
||||
$worksheet_number = 1;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO work_sheets
|
||||
(
|
||||
idmatrice, worksheet_date, customer_name, profile_type_code, 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
|
||||
(
|
||||
?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?,
|
||||
?, ?, ?,
|
||||
?, ?,
|
||||
?, ?, ?, ?,
|
||||
?, ?
|
||||
)
|
||||
");
|
||||
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
|
||||
(
|
||||
?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?
|
||||
)
|
||||
");
|
||||
$stmt->execute([
|
||||
$worksheet_number,
|
||||
$idmatrice,
|
||||
$worksheet_date,
|
||||
$customer_name !== '' ? $customer_name : null,
|
||||
$profile_code !== '' ? $profile_code : null,
|
||||
null, // revision_code = vuoto => revisione 0
|
||||
'active', // worksheet_status
|
||||
$marking,
|
||||
$prod_control !== '' ? $prod_control : null,
|
||||
$freq_cut !== '' ? $freq_cut : null,
|
||||
@ -180,7 +212,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
]);
|
||||
|
||||
$newId = (int)$pdo->lastInsertId();
|
||||
echo json_encode(['success' => true, 'id' => $newId]);
|
||||
$pdo->commit();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $newId,
|
||||
'worksheet_number' => $worksheet_number,
|
||||
'worksheet_number_label' => worksheet_number_label($worksheet_number)
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -399,6 +438,12 @@ function h($v)
|
||||
return htmlspecialchars((string)$v, ENT_QUOTES);
|
||||
}
|
||||
|
||||
function worksheet_number_label($n)
|
||||
{
|
||||
$n = (int)$n;
|
||||
return $n > 0 ? 'FL' . $n : 'Non assegnato';
|
||||
}
|
||||
|
||||
function ws_options($rows, $selectedValue, $defaultValue = '')
|
||||
{
|
||||
$selectedValue = (string)$selectedValue;
|
||||
@ -855,8 +900,20 @@ $isEdit = ($worksheet_id > 0);
|
||||
<div class="value"><?= $isEdit ? 'In modifica' : 'Nuovo foglio' ?></div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="label">ID foglio</div>
|
||||
<div class="value" id="summaryWsId"><?= $worksheet_id > 0 ? (int)$worksheet_id : 'Non salvato' ?></div>
|
||||
<div class="label">Foglio / Revisione</div>
|
||||
<div class="value" id="summaryWsId">
|
||||
<?php
|
||||
$wsNumberLabel = ($worksheet && !empty($worksheet['worksheet_number']))
|
||||
? worksheet_number_label($worksheet['worksheet_number'])
|
||||
: 'Non assegnato';
|
||||
|
||||
$wsRevisionLabel = ($worksheet && isset($worksheet['revision_code']) && trim((string)$worksheet['revision_code']) !== '')
|
||||
? trim((string)$worksheet['revision_code'])
|
||||
: '0';
|
||||
|
||||
echo h($wsNumberLabel . ' / Rev. ' . $wsRevisionLabel);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<div class="label">Mescole inserite</div>
|
||||
@ -1298,11 +1355,14 @@ $isEdit = ($worksheet_id > 0);
|
||||
if (id > 0) {
|
||||
btnAddMix.prop('disabled', false);
|
||||
$('#mixWorksheetId').val(id);
|
||||
summaryWsId.text(id);
|
||||
|
||||
if (!summaryWsId.text().trim()) {
|
||||
summaryWsId.text('Assegnato');
|
||||
}
|
||||
} else {
|
||||
btnAddMix.prop('disabled', true);
|
||||
$('#mixWorksheetId').val('0');
|
||||
summaryWsId.text('Non salvato');
|
||||
summaryWsId.text('Non assegnato');
|
||||
}
|
||||
}
|
||||
enableMixButtonIfSaved();
|
||||
@ -1350,6 +1410,11 @@ $isEdit = ($worksheet_id > 0);
|
||||
}
|
||||
|
||||
wsIdInput.val(data.id);
|
||||
|
||||
if (data.worksheet_number_label) {
|
||||
summaryWsId.text(data.worksheet_number_label);
|
||||
}
|
||||
|
||||
enableMixButtonIfSaved();
|
||||
|
||||
if (!window.location.search.includes('id=')) {
|
||||
@ -1360,7 +1425,7 @@ $isEdit = ($worksheet_id > 0);
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Testata salvata',
|
||||
text: 'Vuoi aggiungere subito le mescole?',
|
||||
text: (data.worksheet_number_label ? ('Foglio ' + data.worksheet_number_label + ' creato correttamente. Vuoi aggiungere subito le mescole?') : 'Vuoi aggiungere subito le mescole?'),
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sì, aggiungi mescole',
|
||||
cancelButtonText: 'No'
|
||||
|
||||
@ -34,192 +34,18 @@ function formatNullable($v, $fallback = '—')
|
||||
return $v !== '' ? $v : $fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX HANDLERS
|
||||
*/
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
|
||||
while (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
try {
|
||||
if ($action === 'get_matrice_worksheets') {
|
||||
$idmatrice = isset($_POST['idmatrice']) ? (int)$_POST['idmatrice'] : 0;
|
||||
if ($idmatrice <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'ID matrice non valido'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ws.id,
|
||||
ws.idmatrice,
|
||||
ws.worksheet_date,
|
||||
ws.customer_name,
|
||||
ws.profile_type_code,
|
||||
ws.marking,
|
||||
ws.approved_by,
|
||||
ws.created_at,
|
||||
ws.updated_at,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM work_sheet_mescole wsm
|
||||
WHERE wsm.worksheet_id = ws.id
|
||||
) AS mix_count
|
||||
FROM work_sheets ws
|
||||
WHERE ws.idmatrice = ?
|
||||
ORDER BY
|
||||
CASE WHEN ws.worksheet_date IS NULL THEN 1 ELSE 0 END,
|
||||
ws.worksheet_date DESC,
|
||||
ws.id DESC
|
||||
");
|
||||
$stmt->execute([$idmatrice]);
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$data = [];
|
||||
foreach ($rows as $r) {
|
||||
$data[] = [
|
||||
'id' => (int)$r['id'],
|
||||
'idmatrice' => (int)$r['idmatrice'],
|
||||
'worksheet_date' => $r['worksheet_date'],
|
||||
'worksheet_date_it' => formatDateIT($r['worksheet_date']),
|
||||
'customer_name' => $r['customer_name'] ?? '',
|
||||
'profile_type_code' => $r['profile_type_code'] ?? '',
|
||||
'marking' => $r['marking'] ?? '',
|
||||
'approved_by' => $r['approved_by'] ?? '',
|
||||
'created_at' => $r['created_at'] ?? '',
|
||||
'created_at_it' => formatDateTimeIT($r['created_at'] ?? ''),
|
||||
'updated_at' => $r['updated_at'] ?? '',
|
||||
'updated_at_it' => formatDateTimeIT($r['updated_at'] ?? ''),
|
||||
'mix_count' => (int)($r['mix_count'] ?? 0)
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'worksheets' => $data
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'get_worksheet_detail') {
|
||||
$worksheetId = isset($_POST['worksheet_id']) ? (int)$_POST['worksheet_id'] : 0;
|
||||
if ($worksheetId <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'ID foglio non valido'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ws.*,
|
||||
m.nome AS matrice_nome,
|
||||
m.cliente AS matrice_cliente
|
||||
FROM work_sheets ws
|
||||
LEFT JOIN matrice m ON m.id = ws.idmatrice
|
||||
WHERE ws.id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$worksheetId]);
|
||||
$ws = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$ws) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Foglio di lavoro non trovato'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmtMix = $pdo->prepare("
|
||||
SELECT
|
||||
wsm.*,
|
||||
me.nome AS mescola_nome,
|
||||
me.nomeuscita AS mescola_uscita
|
||||
FROM work_sheet_mescole wsm
|
||||
LEFT JOIN mescole me ON me.id = wsm.idmescola
|
||||
WHERE wsm.worksheet_id = ?
|
||||
ORDER BY wsm.mix_position ASC, wsm.id ASC
|
||||
");
|
||||
$stmtMix->execute([$worksheetId]);
|
||||
$mixRows = $stmtMix->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'worksheet' => [
|
||||
'id' => (int)$ws['id'],
|
||||
'idmatrice' => (int)$ws['idmatrice'],
|
||||
'matrice_nome' => $ws['matrice_nome'] ?? '',
|
||||
'matrice_cliente' => $ws['matrice_cliente'] ?? '',
|
||||
'worksheet_date' => $ws['worksheet_date'] ?? '',
|
||||
'worksheet_date_it' => formatDateIT($ws['worksheet_date'] ?? ''),
|
||||
'customer_name' => $ws['customer_name'] ?? '',
|
||||
'profile_type_code' => $ws['profile_type_code'] ?? '',
|
||||
'marking' => $ws['marking'] ?? '',
|
||||
'prod_control_measure_settings' => $ws['prod_control_measure_settings'] ?? '',
|
||||
'control_frequency_cut' => $ws['control_frequency_cut'] ?? '',
|
||||
'control_frequency_drawing' => $ws['control_frequency_drawing'] ?? '',
|
||||
'control_frequency_jig' => $ws['control_frequency_jig'] ?? '',
|
||||
'control_mode_jig' => $ws['control_mode_jig'] ?? '',
|
||||
'requested_package_code' => $ws['requested_package_code'] ?? '',
|
||||
'meters_per_package' => $ws['meters_per_package'] ?? '',
|
||||
'meters_per_package_tolerance' => $ws['meters_per_package_tolerance'] ?? '',
|
||||
'meters_per_package_notes' => $ws['meters_per_package_notes'] ?? '',
|
||||
'box_type' => $ws['box_type'] ?? '',
|
||||
'packages_or_pieces_per_box' => $ws['packages_or_pieces_per_box'] ?? '',
|
||||
'meters_per_box' => $ws['meters_per_box'] ?? '',
|
||||
'pallet_type' => $ws['pallet_type'] ?? '',
|
||||
'boxes_or_packages_per_pallet' => $ws['boxes_or_packages_per_pallet'] ?? '',
|
||||
'speed_expected_kg_h' => $ws['speed_expected_kg_h'] ?? '',
|
||||
'speed_actual_kg_h' => $ws['speed_actual_kg_h'] ?? '',
|
||||
'speed_expected_m_h' => $ws['speed_expected_m_h'] ?? '',
|
||||
'speed_actual_m_h' => $ws['speed_actual_m_h'] ?? '',
|
||||
'approved_by' => $ws['approved_by'] ?? '',
|
||||
'notes' => $ws['notes'] ?? '',
|
||||
'created_at' => $ws['created_at'] ?? '',
|
||||
'created_at_it' => formatDateTimeIT($ws['created_at'] ?? ''),
|
||||
'updated_at' => $ws['updated_at'] ?? '',
|
||||
'updated_at_it' => formatDateTimeIT($ws['updated_at'] ?? '')
|
||||
],
|
||||
'mix_rows' => array_map(function ($r) {
|
||||
return [
|
||||
'id' => (int)$r['id'],
|
||||
'mix_position' => (int)$r['mix_position'],
|
||||
'mescola_nome' => $r['mescola_nome'] ?? '',
|
||||
'mescola_uscita' => $r['mescola_uscita'] ?? '',
|
||||
'mix_weight_g_m' => $r['mix_weight_g_m'] ?? '',
|
||||
'required_density' => $r['required_density'] ?? '',
|
||||
'required_hardness_shore_a' => $r['required_hardness_shore_a'] ?? '',
|
||||
'lubrication_type' => $r['lubrication_type'] ?? '',
|
||||
'lubrication_notes' => $r['lubrication_notes'] ?? ''
|
||||
];
|
||||
}, $mixRows)
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Azione AJAX sconosciuta'
|
||||
]);
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
function worksheetNumberLabel($n)
|
||||
{
|
||||
$n = (int)$n;
|
||||
return $n > 0 ? 'FL' . $n : '—';
|
||||
}
|
||||
|
||||
function revisionLabel($rev)
|
||||
{
|
||||
$rev = trim((string)$rev);
|
||||
return $rev !== '' ? $rev : '0';
|
||||
}
|
||||
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="it">
|
||||
@ -524,8 +350,60 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
}
|
||||
|
||||
.modal-worksheet-list {
|
||||
max-width: 980px;
|
||||
width: 94vw;
|
||||
max-width: 1320px;
|
||||
width: 97vw;
|
||||
}
|
||||
|
||||
.worksheet-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: .85rem;
|
||||
}
|
||||
|
||||
.worksheet-badge-rev {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 54px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
background: #e7f1ff;
|
||||
color: #0d6efd;
|
||||
font-weight: 700;
|
||||
font-size: .84rem;
|
||||
}
|
||||
|
||||
.worksheet-badge-status-active {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 88px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
background: #d1e7dd;
|
||||
color: #0f5132;
|
||||
font-weight: 700;
|
||||
font-size: .84rem;
|
||||
}
|
||||
|
||||
.worksheet-badge-status-inactive {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 88px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
background: #f8d7da;
|
||||
color: #842029;
|
||||
font-weight: 700;
|
||||
font-size: .84rem;
|
||||
}
|
||||
|
||||
.modal-worksheet-view {
|
||||
@ -1104,53 +982,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODALE LISTA FOGLI DI LAVORO -->
|
||||
<div class="modal fade" id="worksheetsListModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-worksheet-list">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="background:linear-gradient(135deg,#e7f1ff,#d6e9ff);">
|
||||
<div>
|
||||
<h5 class="modal-title mb-0">
|
||||
<i class="fa-solid fa-clipboard-list me-2"></i>Fogli di lavoro collegati
|
||||
</h5>
|
||||
<small class="text-muted">Elenco fogli associati al profilo selezionato</small>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="wl_idmatrice">
|
||||
<div class="fw-semibold mb-3" id="wl_matrice_name" style="color:#0b3d91;"></div>
|
||||
|
||||
<div id="worksheetsListContainer">
|
||||
<div class="text-muted">Caricamento fogli di lavoro...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODALE DETTAGLIO FOGLIO DI LAVORO -->
|
||||
<div class="modal fade" id="worksheetDetailModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-worksheet-view">
|
||||
<div class="modal-content" style="min-height:92vh;">
|
||||
<div class="modal-header" style="background:linear-gradient(135deg,#ede9fe,#ddd6fe);">
|
||||
<div>
|
||||
<h5 class="modal-title mb-0">
|
||||
<i class="fa-solid fa-file-lines me-2"></i>Dettaglio foglio di lavoro
|
||||
</h5>
|
||||
<small class="text-muted">Visualizzazione completa in sola lettura</small>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body" id="worksheetDetailContainer">
|
||||
<div class="text-muted">Caricamento dettaglio foglio...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODALE PREVIEW FILE -->
|
||||
<div class="modal fade" id="filePreviewModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" style="max-width:1400px; width:98vw;">
|
||||
@ -1164,9 +995,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include('include/worksheets-linked-modals.php'); ?>
|
||||
<?php include('jsinclude.php'); ?>
|
||||
|
||||
<script src="assets/js/worksheets-linked-modals.js"></script>
|
||||
<script>
|
||||
function convertToMySQLDate(dateStr) {
|
||||
if (!dateStr) return "";
|
||||
@ -1221,16 +1052,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic', 'heif'].includes(ext);
|
||||
}
|
||||
|
||||
function valueOrDash(v) {
|
||||
return (v === null || v === undefined || String(v).trim() === '') ? '—' : escapeHtml(v);
|
||||
}
|
||||
|
||||
function renderReadonlyField(label, value) {
|
||||
return `
|
||||
<div class="readonly-label">${escapeHtml(label)}</div>
|
||||
<div class="readonly-value">${valueOrDash(value)}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
let selectedAttachmentFiles = [];
|
||||
|
||||
@ -1421,262 +1242,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
modal.show();
|
||||
}
|
||||
|
||||
function loadMatriceWorksheets(idmatrice, matriceNome) {
|
||||
$("#wl_idmatrice").val(idmatrice);
|
||||
$("#wl_matrice_name").html(`<span class="worksheet-chip"><i class="fa-solid fa-layer-group"></i>${escapeHtml(matriceNome || '')}</span>`);
|
||||
$("#worksheetsListContainer").html('<div class="text-muted">Caricamento fogli di lavoro...</div>');
|
||||
|
||||
fetch(window.location.href, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: 'ajax=1&action=get_matrice_worksheets&idmatrice=' + encodeURIComponent(idmatrice)
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
$("#worksheetsListContainer").html('<div class="text-danger">Errore nel caricamento dei fogli</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
const rows = data.worksheets || [];
|
||||
|
||||
if (!rows.length) {
|
||||
$("#worksheetsListContainer").html('<div class="text-muted">Nessun foglio di lavoro collegato a questo profilo</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped align-middle worksheet-list-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:90px;">ID</th>
|
||||
<th style="width:140px;">Data foglio</th>
|
||||
<th>Cliente</th>
|
||||
<th>Codice profilo</th>
|
||||
<th style="width:110px;">Mescole</th>
|
||||
<th style="width:230px;">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
rows.forEach(r => {
|
||||
html += `
|
||||
<tr>
|
||||
<td><strong>#${r.id}</strong></td>
|
||||
<td>${escapeHtml(r.worksheet_date_it || '—')}</td>
|
||||
<td title="${escapeHtml(r.customer_name || '')}">${escapeHtml(r.customer_name || '—')}</td>
|
||||
<td>${escapeHtml(r.profile_type_code || '—')}</td>
|
||||
<td>${escapeHtml(String(r.mix_count || 0))}</td>
|
||||
<td class="text-nowrap">
|
||||
<button type="button"
|
||||
class="btn btn-view-worksheet open-worksheet-detail"
|
||||
data-id="${r.id}">
|
||||
<i class="fa-solid fa-eye me-1"></i>Apri dettaglio
|
||||
</button>
|
||||
<a class="worksheet-open-link ms-1"
|
||||
href="manage-worksheet.php?id=${r.id}"
|
||||
target="_blank">
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i>Apri pagina
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$("#worksheetsListContainer").html(html);
|
||||
})
|
||||
.catch(() => {
|
||||
$("#worksheetsListContainer").html('<div class="text-danger">Errore nel caricamento dei fogli</div>');
|
||||
});
|
||||
}
|
||||
|
||||
function loadWorksheetDetail(worksheetId) {
|
||||
$("#worksheetDetailContainer").html('<div class="text-muted">Caricamento dettaglio foglio...</div>');
|
||||
|
||||
fetch(window.location.href, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: 'ajax=1&action=get_worksheet_detail&worksheet_id=' + encodeURIComponent(worksheetId)
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
$("#worksheetDetailContainer").html('<div class="text-danger">Errore nel caricamento del dettaglio foglio</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
const ws = data.worksheet || {};
|
||||
const mixRows = data.mix_rows || [];
|
||||
|
||||
let mixHtml = `
|
||||
<div class="text-muted">Nessuna mescola associata</div>
|
||||
`;
|
||||
|
||||
if (mixRows.length) {
|
||||
mixHtml = `
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped align-middle mix-readonly-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:80px;">Pos</th>
|
||||
<th>Mescola</th>
|
||||
<th style="width:120px;">Peso g/m</th>
|
||||
<th style="width:140px;">Densità</th>
|
||||
<th style="width:150px;">Durezza</th>
|
||||
<th style="width:130px;">Lubr.</th>
|
||||
<th>Note lubr.</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
mixRows.forEach(r => {
|
||||
const nomeMescola = r.mescola_uscita ?
|
||||
`${escapeHtml(r.mescola_nome || '—')} <div class="small text-muted">${escapeHtml(r.mescola_uscita)}</div>` :
|
||||
escapeHtml(r.mescola_nome || '—');
|
||||
|
||||
mixHtml += `
|
||||
<tr>
|
||||
<td>${escapeHtml(String(r.mix_position || ''))}</td>
|
||||
<td>${nomeMescola}</td>
|
||||
<td>${valueOrDash(r.mix_weight_g_m)}</td>
|
||||
<td>${valueOrDash(r.required_density)}</td>
|
||||
<td>${valueOrDash(r.required_hardness_shore_a)}</td>
|
||||
<td>${valueOrDash(r.lubrication_type)}</td>
|
||||
<td>${valueOrDash(r.lubrication_notes)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
mixHtml += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const html = `
|
||||
<div class="worksheet-title-box mb-4">
|
||||
<div class="d-flex justify-content-between align-items-start gap-3 flex-wrap">
|
||||
<div>
|
||||
<h4 class="mb-1">Foglio di lavoro #${escapeHtml(String(ws.id || ''))}</h4>
|
||||
<small>Profilo: ${escapeHtml(ws.matrice_nome || '—')} ${ws.matrice_cliente ? '• Cliente matrice: ' + escapeHtml(ws.matrice_cliente) : ''}</small>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage-worksheet.php?id=${escapeHtml(String(ws.id || ''))}"
|
||||
target="_blank"
|
||||
class="worksheet-open-link">
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i>
|
||||
Apri foglio completo
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Dati principali</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField('ID foglio', ws.id)}
|
||||
${renderReadonlyField('Data foglio', ws.worksheet_date_it)}
|
||||
${renderReadonlyField('Cliente override', ws.customer_name)}
|
||||
${renderReadonlyField('Codice profilo', ws.profile_type_code)}
|
||||
${renderReadonlyField('Marchiatura', ws.marking)}
|
||||
${renderReadonlyField('Approvato da', ws.approved_by)}
|
||||
${renderReadonlyField('Creato il', ws.created_at_it)}
|
||||
${renderReadonlyField('Ultimo aggiornamento', ws.updated_at_it)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Controlli produzione</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField('Taglio', ws.control_frequency_cut)}
|
||||
${renderReadonlyField('Disegno', ws.control_frequency_drawing)}
|
||||
${renderReadonlyField('Dima', ws.control_frequency_jig)}
|
||||
${renderReadonlyField('Modalità dima', ws.control_mode_jig)}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="readonly-label mb-2">Impostazione misure controllo produzione</div>
|
||||
<div class="readonly-value" style="white-space:pre-wrap;">${valueOrDash(ws.prod_control_measure_settings)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Packaging / Confezionamento</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField('Codice confezione', ws.requested_package_code)}
|
||||
${renderReadonlyField('Metri per confezione', ws.meters_per_package)}
|
||||
${renderReadonlyField('Tolleranza metri/conf.', ws.meters_per_package_tolerance)}
|
||||
${renderReadonlyField('Scatola tipo', ws.box_type)}
|
||||
${renderReadonlyField('Conf./pezzi per scatola', ws.packages_or_pieces_per_box)}
|
||||
${renderReadonlyField('Metri per scatola', ws.meters_per_box)}
|
||||
${renderReadonlyField('Bancale tipo', ws.pallet_type)}
|
||||
${renderReadonlyField('Scatole/conf. per bancale', ws.boxes_or_packages_per_pallet)}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="readonly-label mb-2">Note metri / confezione</div>
|
||||
<div class="readonly-value" style="white-space:pre-wrap;">${valueOrDash(ws.meters_per_package_notes)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Velocità e note</div>
|
||||
<div class="readonly-card-body">
|
||||
<div class="readonly-grid">
|
||||
${renderReadonlyField('Vel. prevista kg/h', ws.speed_expected_kg_h)}
|
||||
${renderReadonlyField('Vel. effettiva kg/h', ws.speed_actual_kg_h)}
|
||||
${renderReadonlyField('Vel. prevista m/h', ws.speed_expected_m_h)}
|
||||
${renderReadonlyField('Vel. effettiva m/h', ws.speed_actual_m_h)}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="readonly-label mb-2">Note</div>
|
||||
<div class="readonly-value" style="white-space:pre-wrap;">${valueOrDash(ws.notes)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="readonly-card">
|
||||
<div class="readonly-card-header">Mescole associate al foglio</div>
|
||||
<div class="readonly-card-body">
|
||||
${mixHtml}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$("#worksheetDetailContainer").html(html);
|
||||
})
|
||||
.catch(() => {
|
||||
$("#worksheetDetailContainer").html('<div class="text-danger">Errore nel caricamento del dettaglio foglio</div>');
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#tabellaMatrici').DataTable({
|
||||
@ -2117,21 +1682,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['aj
|
||||
$("#filePreviewContainer").html("");
|
||||
});
|
||||
|
||||
// OPEN WORKSHEETS LIST
|
||||
$(document).on("click", ".worksheets, .show-worksheets", function() {
|
||||
const idmatrice = $(this).data("id");
|
||||
const nome = $(this).data("nome") || "";
|
||||
|
||||
loadMatriceWorksheets(idmatrice, nome);
|
||||
new bootstrap.Modal(document.getElementById('worksheetsListModal')).show();
|
||||
});
|
||||
|
||||
// OPEN WORKSHEET DETAIL
|
||||
$(document).on("click", ".open-worksheet-detail", function() {
|
||||
const worksheetId = $(this).data("id");
|
||||
loadWorksheetDetail(worksheetId);
|
||||
new bootstrap.Modal(document.getElementById('worksheetDetailModal')).show();
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("click", ".thumb-img", function() {
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user