zibo-dashboard/public/userarea/manage-worksheet.php
2026-03-06 08:42:18 +01:00

1052 lines
47 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
ob_start(); // buffer any accidental output
ini_set('display_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$worksheet_id = isset($_GET['id']) && is_numeric($_GET['id']) ? (int)$_GET['id'] : 0;
// AJAX HANDLERS
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
// Ensure clean JSON output (remove any echoed HTML/notices)
while (ob_get_level()) {
ob_end_clean();
}
header('Content-Type: application/json; charset=utf-8');
header('Content-Type: application/json');
$action = $_POST['action'] ?? '';
try {
// Save header (insert/update)
if ($action === 'save_header') {
$idmatrice = (int)($_POST['idmatrice'] ?? 0);
if ($idmatrice <= 0) {
echo json_encode(['success' => false, 'message' => 'Seleziona una matrice/profilo']);
exit;
}
$id = (int)($_POST['id'] ?? 0);
$worksheet_date = $_POST['worksheet_date'] !== '' ? $_POST['worksheet_date'] : null;
$customer_name = trim($_POST['customer_name'] ?? '');
$profile_code = trim($_POST['profile_type_code'] ?? '');
$marking = ($_POST['marking'] ?? '') !== '' ? $_POST['marking'] : null;
$prod_control = trim($_POST['prod_control_measure_settings'] ?? '');
$freq_cut = trim($_POST['control_frequency_cut'] ?? '');
$freq_draw = trim($_POST['control_frequency_drawing'] ?? '');
$freq_jig = trim($_POST['control_frequency_jig'] ?? '');
$mode_jig = trim($_POST['control_mode_jig'] ?? '');
$box_type = trim($_POST['box_type'] ?? '');
$pkg_box = $_POST['packages_or_pieces_per_box'] !== '' ? (int)$_POST['packages_or_pieces_per_box'] : null;
$m_box = $_POST['meters_per_box'] !== '' ? (int)$_POST['meters_per_box'] : null;
$pallet_type = trim($_POST['pallet_type'] ?? '');
$per_pallet = $_POST['boxes_or_packages_per_pallet'] !== '' ? (int)$_POST['boxes_or_packages_per_pallet'] : null;
$sp_exp_kg = $_POST['speed_expected_kg_h'] !== '' ? (float)$_POST['speed_expected_kg_h'] : null;
$sp_act_kg = $_POST['speed_actual_kg_h'] !== '' ? (float)$_POST['speed_actual_kg_h'] : null;
$sp_exp_m = $_POST['speed_expected_m_h'] !== '' ? (float)$_POST['speed_expected_m_h'] : null;
$sp_act_m = $_POST['speed_actual_m_h'] !== '' ? (float)$_POST['speed_actual_m_h'] : null;
$approved_by = trim($_POST['approved_by'] ?? '');
$notes = trim($_POST['notes'] ?? '');
if ($id > 0) {
$stmt = $pdo->prepare("
UPDATE work_sheets SET
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 = ?,
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 = ?
WHERE id = ?
");
$stmt->execute([
$idmatrice,
$worksheet_date,
$customer_name !== '' ? $customer_name : null,
$profile_code !== '' ? $profile_code : null,
$marking,
$prod_control !== '' ? $prod_control : null,
$freq_cut !== '' ? $freq_cut : null,
$freq_draw !== '' ? $freq_draw : null,
$freq_jig !== '' ? $freq_jig : null,
$mode_jig !== '' ? $mode_jig : null,
$box_type !== '' ? $box_type : null,
$pkg_box,
$m_box,
$pallet_type !== '' ? $pallet_type : null,
$per_pallet,
$sp_exp_kg,
$sp_act_kg,
$sp_exp_m,
$sp_act_m,
$approved_by !== '' ? $approved_by : null,
$notes !== '' ? $notes : null,
$id
]);
echo json_encode(['success' => true, 'id' => $id]);
exit;
}
$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,
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([
$idmatrice,
$worksheet_date,
$customer_name !== '' ? $customer_name : null,
$profile_code !== '' ? $profile_code : null,
$marking,
$prod_control !== '' ? $prod_control : null,
$freq_cut !== '' ? $freq_cut : null,
$freq_draw !== '' ? $freq_draw : null,
$freq_jig !== '' ? $freq_jig : null,
$mode_jig !== '' ? $mode_jig : null,
$box_type !== '' ? $box_type : null,
$pkg_box,
$m_box,
$pallet_type !== '' ? $pallet_type : null,
$per_pallet,
$sp_exp_kg,
$sp_act_kg,
$sp_exp_m,
$sp_act_m,
$approved_by !== '' ? $approved_by : null,
$notes !== '' ? $notes : null
]);
$newId = (int)$pdo->lastInsertId();
echo json_encode(['success' => true, 'id' => $newId]);
exit;
}
// Add or edit mix row
if ($action === 'save_mix_row') {
$worksheet_id = (int)($_POST['worksheet_id'] ?? 0);
if ($worksheet_id <= 0) {
echo json_encode(['success' => false, 'message' => 'Salva prima il foglio (testata)']);
exit;
}
$row_id = (int)($_POST['row_id'] ?? 0);
$idmescola = (int)($_POST['idmescola'] ?? 0);
$pos = 0; // auto-assign
if ($idmescola <= 0) {
echo json_encode(['success' => false, 'message' => 'Seleziona una mescola']);
exit;
}
if ($pos <= 0) $pos = 1;
$mix_weight = $_POST['mix_weight_g_m'] !== '' ? (float)$_POST['mix_weight_g_m'] : null;
$density = trim($_POST['required_density'] ?? '');
$hardness = trim($_POST['required_hardness_shore_a'] ?? '');
$lub_type = ($_POST['lubrication_type'] ?? '') !== '' ? $_POST['lubrication_type'] : null;
$lub_note = trim($_POST['lubrication_notes'] ?? '');
$pkg_code = trim($_POST['requested_package_code'] ?? '');
$m_pkg = $_POST['meters_per_package'] !== '' ? (int)$_POST['meters_per_package'] : null;
$m_pkg_note = trim($_POST['meters_per_package_notes'] ?? '');
$m_pkg_tol = trim($_POST['meters_per_package_tolerance'] ?? '');
// Use transaction to keep constraints consistent
$pdo->beginTransaction();
if ($row_id > 0) {
// Auto-assign mix_position = max + 1 for this worksheet
$stmtPos = $pdo->prepare("
SELECT IFNULL(MAX(mix_position), 0) + 1
FROM work_sheet_mescole
WHERE worksheet_id = ?
FOR UPDATE
");
$stmtPos->execute([$worksheet_id]);
$pos = (int)$stmtPos->fetchColumn();
if ($pos <= 0) $pos = 1;
$stmt = $pdo->prepare("
UPDATE work_sheet_mescole SET
idmescola = ?,
mix_weight_g_m = ?,
required_density = ?,
required_hardness_shore_a = ?,
lubrication_type = ?,
lubrication_notes = ?,
requested_package_code = ?,
meters_per_package = ?,
meters_per_package_notes = ?,
meters_per_package_tolerance = ?
WHERE id = ? AND worksheet_id = ?
");
$stmt->execute([
$idmescola,
$mix_weight,
$density !== '' ? $density : null,
$hardness !== '' ? $hardness : null,
$lub_type,
$lub_note !== '' ? $lub_note : null,
$pkg_code !== '' ? $pkg_code : null,
$m_pkg,
$m_pkg_note !== '' ? $m_pkg_note : null,
$m_pkg_tol !== '' ? $m_pkg_tol : null,
$row_id,
$worksheet_id
]);
$pdo->commit();
echo json_encode(['success' => true]);
exit;
}
// If position already used, auto-assign next (max+1)
$chk = $pdo->prepare("SELECT COUNT(*) FROM work_sheet_mescole WHERE worksheet_id = ? AND mix_position = ?");
$chk->execute([$worksheet_id, $pos]);
if ((int)$chk->fetchColumn() > 0) {
$mx = $pdo->prepare("SELECT IFNULL(MAX(mix_position),0) + 1 FROM work_sheet_mescole WHERE worksheet_id = ?");
$mx->execute([$worksheet_id]);
$pos = (int)$mx->fetchColumn();
}
$stmt = $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,
requested_package_code, meters_per_package, meters_per_package_notes, meters_per_package_tolerance)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$worksheet_id,
$idmescola,
$pos,
$mix_weight,
$density !== '' ? $density : null,
$hardness !== '' ? $hardness : null,
$lub_type,
$lub_note !== '' ? $lub_note : null,
$pkg_code !== '' ? $pkg_code : null,
$m_pkg,
$m_pkg_note !== '' ? $m_pkg_note : null,
$m_pkg_tol !== '' ? $m_pkg_tol : null
]);
$pdo->commit();
echo json_encode(['success' => true]);
exit;
}
// Delete mix row
if ($action === 'delete_mix_row') {
$row_id = (int)($_POST['row_id'] ?? 0);
if ($row_id <= 0) {
echo json_encode(['success' => false, 'message' => 'ID riga non valido']);
exit;
}
$stmt = $pdo->prepare("DELETE FROM work_sheet_mescole WHERE id = ?");
$stmt->execute([$row_id]);
echo json_encode(['success' => true]);
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;
}
}
// Load matrices dropdown
$matrici = $pdo->query("
SELECT id, nome, cliente
FROM matrice
ORDER BY nome ASC
")->fetchAll(PDO::FETCH_ASSOC);
// Load worksheet lookup options
$lookup = [];
$lookupDefault = [];
$stmt = $pdo->prepare("
SELECT category, value, label, is_default
FROM ws_lookup_options
WHERE is_active = 1
ORDER BY category ASC, sort_order ASC, label ASC
");
$stmt->execute();
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
$lookup[$r['category']][] = $r;
if ((int)$r['is_default'] === 1 && !isset($lookupDefault[$r['category']])) {
$lookupDefault[$r['category']] = $r['value'];
}
}
// Load mescole dropdown for modal
$mescole = $pdo->query("
SELECT id, nome, nomeuscita
FROM mescole
ORDER BY nome ASC
")->fetchAll(PDO::FETCH_ASSOC);
// Load worksheet (edit)
$worksheet = null;
$mixRows = [];
if ($worksheet_id > 0) {
$stmt = $pdo->prepare("
SELECT ws.*, m.nome AS matrice_nome
FROM work_sheets ws
LEFT JOIN matrice m ON ws.idmatrice = m.id
WHERE ws.id = ?
");
$stmt->execute([$worksheet_id]);
$worksheet = $stmt->fetch(PDO::FETCH_ASSOC);
if ($worksheet) {
$stmt = $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
");
$stmt->execute([$worksheet_id]);
$mixRows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$worksheet_id = 0;
}
}
// Helpers
function h($v)
{
return htmlspecialchars((string)$v, ENT_QUOTES);
}
function ws_options($rows, $selectedValue, $defaultValue = '')
{
$selectedValue = (string)$selectedValue;
if ($selectedValue === '' && $defaultValue !== '') {
$selectedValue = (string)$defaultValue;
}
$html = '<option value="">--</option>';
if (!$rows) return $html;
foreach ($rows as $r) {
$val = h($r['value']);
$lab = h($r['label']);
$sel = ((string)$r['value'] === $selectedValue) ? ' selected' : '';
$html .= "<option value=\"{$val}\"{$sel}>{$lab}</option>";
}
return $html;
}
$isEdit = ($worksheet_id > 0);
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php include('cssinclude.php'); ?>
<title><?= $isEdit ? 'Modifica Foglio di Lavoro' : 'Nuovo Foglio di Lavoro' ?></title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<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;
background: #f8fafc;
}
.card {
border-radius: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.back-dashboard {
background: #cfe3ff !important;
color: #1f2d3d !important;
border: 1px solid #bcd4f4 !important;
border-radius: 10px;
font-weight: 600;
padding: 10px 18px;
}
.btn-add {
background: #0d6efd;
color: white;
border-radius: 8px;
padding: 10px 20px;
font-weight: 500;
}
.table thead {
background: #cfe3ff;
color: #1f2d3d;
}
.modal-content {
border-radius: 16px;
}
.section-title {
font-weight: 700;
color: #1f2d3d;
}
.small-hint {
color: #6b7280;
font-size: 0.85rem;
}
</style>
</head>
<body>
<div class="wrapper toggled">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="card p-3">
<div class="card-header d-flex justify-content-between align-items-center">
<div>
<h5 class="mb-0"><?= $isEdit ? 'Modifica Foglio di Lavoro' : 'Nuovo Foglio di Lavoro' ?></h5>
<div class="small-hint">Prima salva la testata, poi aggiungi le mescole con il modale</div>
</div>
<div class="d-flex gap-2">
<button class="btn back-dashboard" onclick="location.href='worksheets.php'">↩️ Storico</button>
</div>
</div>
<div class="card-body">
<!-- HEADER FORM -->
<form id="worksheetHeaderForm">
<input type="hidden" name="id" id="wsId" value="<?= (int)$worksheet_id ?>">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-semibold">Matrice / Profilo *</label>
<select class="form-select" name="idmatrice" id="idmatrice" required>
<option value="">-- Seleziona --</option>
<?php foreach ($matrici as $m): ?>
<option value="<?= (int)$m['id'] ?>"
<?= $worksheet && (int)$worksheet['idmatrice'] === (int)$m['id'] ? 'selected' : '' ?>>
<?= h($m['nome']) ?><?= $m['cliente'] ? ' — ' . h($m['cliente']) : '' ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Data foglio</label>
<input type="date" class="form-control" name="worksheet_date"
value="<?= $worksheet ? h($worksheet['worksheet_date']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Codice profilo</label>
<input type="text" class="form-control" name="profile_type_code"
value="<?= $worksheet ? h($worksheet['profile_type_code']) : '' ?>">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Cliente (override)</label>
<input type="text" class="form-control" name="customer_name"
value="<?= $worksheet ? h($worksheet['customer_name']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Marchiatura</label>
<select class="form-select" name="marking" id="marking">
<?= ws_options($lookup['marking'] ?? [], $worksheet['marking'] ?? '', $lookupDefault['marking'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Visto / Approvazione</label>
<input type="text" class="form-control" name="approved_by"
value="<?= $worksheet ? h($worksheet['approved_by']) : '' ?>">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Impostazione misure controllo produzione</label>
<textarea class="form-control" name="prod_control_measure_settings" rows="2"><?= $worksheet ? h($worksheet['prod_control_measure_settings']) : '' ?></textarea>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Controlli - Taglio</label>
<select class="form-select" name="control_frequency_cut" id="control_frequency_cut">
<?= ws_options($lookup['control_frequency_cut'] ?? [], $worksheet['control_frequency_cut'] ?? '', $lookupDefault['control_frequency_cut'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Controlli - Disegno</label>
<select class="form-select" name="control_frequency_drawing" id="control_frequency_drawing">
<?= ws_options($lookup['control_frequency_drawing'] ?? [], $worksheet['control_frequency_drawing'] ?? '', $lookupDefault['control_frequency_drawing'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Controlli - Dima</label>
<select class="form-select" name="control_frequency_jig" id="control_frequency_jig">
<?= ws_options($lookup['control_frequency_jig'] ?? [], $worksheet['control_frequency_jig'] ?? '', $lookupDefault['control_frequency_jig'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Modalità dima</label>
<select class="form-select" name="control_mode_jig" id="control_mode_jig">
<?= ws_options($lookup['control_mode_jig'] ?? [], $worksheet['control_mode_jig'] ?? '', $lookupDefault['control_mode_jig'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Scatola (tipo)</label>
<select class="form-select" name="box_type" id="box_type">
<?= ws_options($lookup['box_type'] ?? [], $worksheet['box_type'] ?? '', $lookupDefault['box_type'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">N° conf./pezzi per scatola</label>
<input type="number" class="form-control" name="packages_or_pieces_per_box"
value="<?= $worksheet ? h($worksheet['packages_or_pieces_per_box']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Metri per scatola</label>
<input type="number" class="form-control" name="meters_per_box"
value="<?= $worksheet ? h($worksheet['meters_per_box']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Bancale (tipo)</label>
<select class="form-select" name="pallet_type" id="pallet_type">
<?= ws_options($lookup['pallet_type'] ?? [], $worksheet['pallet_type'] ?? '', $lookupDefault['pallet_type'] ?? '') ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Scatole/conf. per bancale</label>
<input type="number" class="form-control" name="boxes_or_packages_per_pallet"
value="<?= $worksheet ? h($worksheet['boxes_or_packages_per_pallet']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Vel. prevista (kg/h)</label>
<input type="number" step="0.01" class="form-control" name="speed_expected_kg_h"
value="<?= $worksheet ? h($worksheet['speed_expected_kg_h']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Vel. effettiva (kg/h)</label>
<input type="number" step="0.01" class="form-control" name="speed_actual_kg_h"
value="<?= $worksheet ? h($worksheet['speed_actual_kg_h']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Vel. prevista (m/h)</label>
<input type="number" step="0.01" class="form-control" name="speed_expected_m_h"
value="<?= $worksheet ? h($worksheet['speed_expected_m_h']) : '' ?>">
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">Vel. effettiva (m/h)</label>
<input type="number" step="0.01" class="form-control" name="speed_actual_m_h"
value="<?= $worksheet ? h($worksheet['speed_actual_m_h']) : '' ?>">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Note</label>
<textarea class="form-control" name="notes" rows="2"><?= $worksheet ? h($worksheet['notes']) : '' ?></textarea>
</div>
<div class="col-12 d-flex justify-content-center gap-2 mt-2">
<button type="submit" class="btn btn-add">💾 Salva Testata</button>
<button type="button" class="btn btn-outline-primary"
id="btnAddMix" data-bs-toggle="modal" data-bs-target="#mixModal" disabled>
Aggiungi Mescola
</button>
</div>
</div>
</form>
<hr class="my-4">
<!-- MIX ROWS TABLE -->
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="section-title">Mescole associate al foglio</div>
<div class="small-hint">Usa “Aggiungi Mescola” per inserire una o più righe</div>
</div>
<div class="table-responsive">
<table id="tabellaMixRows" class="table table-striped table-bordered">
<thead>
<tr>
<th>Pos</th>
<th>Mescola</th>
<th>Peso (g/m)</th>
<th>Densità</th>
<th>Durezza</th>
<th>Lubr.</th>
<th>Confez.</th>
<th>m/conf.</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($mixRows as $r): ?>
<tr>
<td><?= (int)$r['mix_position'] ?></td>
<td>
<?= h($r['mescola_nome'] ?? '-') ?>
<?php if (!empty($r['mescola_uscita'])): ?>
<div class="small-hint"><?= h($r['mescola_uscita']) ?></div>
<?php endif; ?>
</td>
<td><?= h($r['mix_weight_g_m'] ?? '-') ?></td>
<td><?= h($r['required_density'] ?? '-') ?></td>
<td><?= h($r['required_hardness_shore_a'] ?? '-') ?></td>
<td><?= h($r['lubrication_type'] ?? '-') ?></td>
<td><?= h($r['requested_package_code'] ?? '-') ?></td>
<td><?= h($r['meters_per_package'] ?? '-') ?></td>
<td class="text-nowrap">
<button class="btn btn-sm btn-outline-primary edit-mix"
data-row='<?= h(json_encode($r, JSON_UNESCAPED_UNICODE)) ?>'>
✏️ Modifica
</button>
<button class="btn btn-sm btn-outline-danger delete-mix"
data-id="<?= (int)$r['id'] ?>">
🗑️
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<!-- MODAL MIX -->
<div class="modal fade" id="mixModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background:#cfe3ff;">
<h5 class="modal-title" id="mixModalTitle">Aggiungi Mescola</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="mixForm">
<input type="hidden" name="worksheet_id" id="mixWorksheetId" value="<?= (int)$worksheet_id ?>">
<input type="hidden" name="row_id" id="mixRowId" value="0">
<div class="row g-3">
<div class="col-md-8">
<label class="form-label fw-semibold">Mescola *</label>
<select class="form-select" name="idmescola" id="idmescola" required>
<option value="">-- Seleziona --</option>
<?php foreach ($mescole as $me): ?>
<option value="<?= (int)$me['id'] ?>">
<?= h($me['nome']) ?><?= $me['nomeuscita'] ? ' — ' . h($me['nomeuscita']) : '' ?>
</option>
<?php endforeach; ?>
</select>
</div>
<input type="hidden" name="mix_position" id="mix_position" value="">
<div class="col-md-4">
<label class="form-label fw-semibold">Peso metro mescola (g/m)</label>
<input type="number" step="0.01" class="form-control" name="mix_weight_g_m" id="mix_weight_g_m">
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Densità richiesta</label>
<input type="text" class="form-control" name="required_density" id="required_density" placeholder="es. 1,22 +/- 0,03">
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Durezza richiesta (shore A)</label>
<input type="text" class="form-control" name="required_hardness_shore_a" id="required_hardness_shore_a" placeholder="es. 70 +/- 5">
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Lubrificazione</label>
<select class="form-select" name="lubrication_type" id="lubrication_type">
<?= ws_options($lookup['lubrication_type'] ?? [], '', $lookupDefault['lubrication_type'] ?? '') ?>
</select>
</div>
<div class="col-md-8">
<label class="form-label fw-semibold">Note lubrificazione</label>
<input type="text" class="form-control" name="lubrication_notes" id="lubrication_notes">
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Codice confezione</label>
<select class="form-select" name="requested_package_code" id="requested_package_code">
<?= ws_options($lookup['requested_package_code'] ?? [], '', $lookupDefault['requested_package_code'] ?? '') ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Metri per confezione</label>
<input type="number" class="form-control" name="meters_per_package" id="meters_per_package">
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Tolleranza metri/confezione</label>
<input type="text" class="form-control" name="meters_per_package_tolerance" id="meters_per_package_tolerance" placeholder="es. +/- 4m">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Note metri/confezione</label>
<input type="text" class="form-control" name="meters_per_package_notes" id="meters_per_package_notes">
</div>
<div class="col-12 text-center mt-2">
<button type="submit" class="btn btn-add">💾 Salva Mescola</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
$(document).ready(function() {
const wsIdInput = $('#wsId');
const btnAddMix = $('#btnAddMix');
if ($('#idmatrice').length) {
$('#idmatrice').select2({
theme: 'bootstrap4',
width: '100%',
placeholder: '-- Seleziona --',
allowClear: true
});
}
$('#mixModal').on('shown.bs.modal', function() {
if (!$('#idmescola').data('select2')) {
$('#idmescola').select2({
theme: 'bootstrap4',
width: '100%',
dropdownParent: $('#mixModal'),
placeholder: '-- Seleziona --',
allowClear: true
});
}
});
function enableMixButtonIfSaved() {
const id = parseInt(wsIdInput.val() || '0', 10);
if (id > 0) {
btnAddMix.prop('disabled', false);
$('#mixWorksheetId').val(id);
} else {
btnAddMix.prop('disabled', true);
$('#mixWorksheetId').val('0');
}
}
enableMixButtonIfSaved();
$('#tabellaMixRows').DataTable({
pageLength: 25,
lengthMenu: [10, 25, 50, 100],
order: [
[0, 'asc']
],
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
}
});
// Save header
$('#worksheetHeaderForm').on('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
formData.append('ajax', '1');
formData.append('action', 'save_header');
fetch(window.location.href, {
method: 'POST',
body: new URLSearchParams(formData)
})
.then(async (r) => {
const text = await r.text();
// Debug: if server returns warnings/HTML, you'll see it in console
try {
return JSON.parse(text);
} catch (err) {
console.error('Response is not valid JSON:', text);
throw new Error('Risposta non JSON (vedi console)');
}
})
.then(data => {
if (!data.success) {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
return;
}
wsIdInput.val(data.id);
enableMixButtonIfSaved();
// If new, update URL to edit mode
if (!window.location.search.includes('id=')) {
const newUrl = 'manage-worksheet.php?id=' + data.id;
window.history.replaceState({}, '', newUrl);
}
// ✅ What you want: confirm + stay on page + open modal if user wants
Swal.fire({
icon: 'success',
title: 'Testata salvata',
text: 'Vuoi aggiungere subito le mescole?',
showCancelButton: true,
confirmButtonText: 'Sì, aggiungi mescole',
cancelButtonText: 'No'
}).then(res => {
if (res.isConfirmed) {
const modal = new bootstrap.Modal(document.getElementById('mixModal'));
modal.show();
}
});
})
.catch(err => {
Swal.fire({
icon: 'error',
title: 'Errore AJAX',
text: err.message
});
});
});
// Prepare modal for add
$('#mixModal').on('show.bs.modal', function() {
const wsId = parseInt(wsIdInput.val() || '0', 10);
if (wsId <= 0) {
Swal.fire({
icon: 'warning',
title: 'Salva prima la testata',
timer: 1200
});
return false;
}
// Reset for add by default
$('#mixModalTitle').text('Aggiungi Mescola');
$('#mixForm')[0].reset();
$('#mixRowId').val('0');
$('#mixWorksheetId').val(wsId);
$('#idmescola').prop('disabled', false);
});
// Edit mix row
$(document).on('click', '.edit-mix', function() {
let row = $(this).attr('data-row');
row = JSON.parse(row);
// Titolo modale
$('#mixModalTitle').text('Modifica Mescola');
// NON resettare in "add"
$('#mixForm')[0].reset();
// Set id riga e worksheet
$('#mixRowId').val(row.id);
$('#mixWorksheetId').val(row.worksheet_id);
// Mescola (se usi select2 devi triggerare change)
$('#idmescola').prop('disabled', false);
$('#idmescola').val(row.idmescola).trigger('change');
// Campi
$('#mix_weight_g_m').val(row.mix_weight_g_m ?? '');
$('#required_density').val(row.required_density ?? '');
$('#required_hardness_shore_a').val(row.required_hardness_shore_a ?? '');
$('#lubrication_type').val(row.lubrication_type ?? '');
$('#lubrication_notes').val(row.lubrication_notes ?? '');
$('#requested_package_code').val(row.requested_package_code ?? '');
$('#meters_per_package').val(row.meters_per_package ?? '');
$('#meters_per_package_tolerance').val(row.meters_per_package_tolerance ?? '');
$('#meters_per_package_notes').val(row.meters_per_package_notes ?? '');
// Apri modale
const modal = new bootstrap.Modal(document.getElementById('mixModal'));
modal.show();
});
// Save mix row
$('#mixForm').on('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
formData.append('ajax', '1');
formData.append('action', 'save_mix_row');
fetch('', {
method: 'POST',
body: new URLSearchParams(formData)
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Salvata!',
timer: 800
})
.then(() => location.reload());
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
}
});
});
// Delete mix row
$(document).on('click', '.delete-mix', function() {
const rowId = $(this).data('id');
Swal.fire({
title: 'Eliminare questa mescola dal foglio?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Sì, elimina',
cancelButtonText: 'Annulla'
}).then(result => {
if (!result.isConfirmed) return;
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `ajax=1&action=delete_mix_row&row_id=${rowId}`
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Eliminata!',
timer: 800
})
.then(() => location.reload());
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
}
});
});
});
});
</script>
</body>
</html>