theloftstore/public/userarea/import_edit2.php
2025-09-18 12:00:43 +02:00

1141 lines
62 KiB
PHP

<?php
// Abilita errori per debug
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/import_debug.log');
if (!file_exists(__DIR__ . '/import_debug.log')) {
file_put_contents(__DIR__ . '/import_debug.log', "Inizio importazione alle " . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
}
// Log iniziale
error_log("Inizio importazione alle " . date('Y-m-d H:i:s'));
include('include/headscript.php');
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !isset($_POST['selected_rows']) || !isset($_POST['filename'])) {
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
exit;
}
$template_id = intval($_POST['template_id']) ?? $_SESSION['template_id'];
$selected_rows = $_POST['selected_rows'] ?? $_SESSION['selected_rows'];
$columns = json_decode($_POST['columns'], true) ?? $_SESSION['columns'];
$rows = json_decode($_POST['rows'], true) ?? $_SESSION['rows'];
$newFilename = htmlspecialchars($_POST['filename']) ?? $_SESSION['filename'];
// Log dei dati ricevuti
error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows));
error_log("Columns: " . json_encode($columns));
error_log("Rows: " . json_encode($rows));
// Recupera l'ID dell'utente loggato
$user_id = $iduserlogin ?? 1;
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
// Genera un UUID univoco per importreferencecode
$importReferenceCode = date('YmdHis') . '-' . uniqid();
// Recupera tutti i mapping dal template
$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field FROM template_mapping WHERE template_id = ?");
$stmt->execute([$template_id]);
$allMappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($allMappings)) {
header("Location: import_xls.php?id=$template_id&status=error&message=" . urlencode("Nessun mapping trovato per il template"));
exit;
}
// Trova il campo main_field
$mainFieldMapping = null;
foreach ($allMappings as $mapping) {
if ($mapping['main_field'] == 1) {
$mainFieldMapping = $mapping;
break;
}
}
$insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids'];
// Recupera i dati appena inseriti con i nomi degli utenti
$stmt = $pdo->prepare("
SELECT d.*, CONCAT(u.first_name, ' ', u.last_name) AS user_name
FROM datadb d
LEFT JOIN auth_users u ON d.user_id = u.id
WHERE d.iddatadb IN (" . implode(',', array_fill(0, count($insertedIds), '?')) . ")
");
$stmt->execute($insertedIds);
$importedData = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Recupera i dettagli manuali da import_data_details
$stmt = $pdo->prepare("
SELECT d.id AS detail_id, d.id AS datadb_id, d.mapping_id, d.field_value, m.field_label, m.data_type, m.is_required, m.manual_default
FROM import_data_details d
JOIN template_mapping m ON d.mapping_id = m.id
WHERE d.id IN (" . implode(',', array_fill(0, count($insertedIds), '?')) . ")
");
$stmt->execute($insertedIds);
$manualDetails = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Recupera il mapping globale per mostrare gli slug leggibili
$stmt = $pdo->query("SELECT mysql_column_name, user_friendly_slug FROM column_mapping");
$slugMapping = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$slugMapping[$row['mysql_column_name']] = $row['user_friendly_slug'];
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<?php include('cssinclude.php'); ?>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2Lw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
.cell-changed {
background-color: #fff3b0 !important;
transition: background-color 0.3s ease;
}
input.auto-input,
select.auto-input {
background-color: #d4edda;
}
input.manual-input,
select.manual-input {
background-color: #fff3cd;
}
input.required-input,
select.required-input {
background-color: #f8d7da;
}
input,
select {
width: 100%;
box-sizing: border-box;
border: 1px solid #ced4da;
border-radius: 4px;
padding: 5px;
font-size: 14px;
}
input,
select {
color: #333;
}
.status-badge {
display: inline-block;
padding: 2px 8px;
font-size: 12px;
font-weight: 500;
border-radius: 12px;
text-align: center;
min-width: 60px;
}
.status-i {
background-color: #ffc107;
color: #212529;
}
.status-P {
background-color: #007bff;
color: white;
}
.status-l {
background-color: #28a745;
color: white;
}
.grid-container {
overflow-x: auto;
max-width: 100%;
margin-bottom: 20px;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.grid-row {
display: flex;
align-items: center;
padding: 0;
border-bottom: 1px solid #dee2e6;
}
.grid-row:last-child {
border-bottom: none;
}
.grid-row:nth-child(even) {
background-color: #f8f9fa;
}
.grid-row:hover {
background-color: #e9ecef;
}
.grid-header,
.grid-cell {
flex: 1;
min-width: 70px;
padding: 12px 15px;
border-right: 1px solid #dee2e6;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: max-width 0.3s ease;
box-sizing: border-box;
}
.grid-header {
font-weight: 600;
background-color: #e9ecef;
color: #495057;
border-bottom: 2px solid #dee2e6;
position: relative;
}
.grid-header:last-child,
.grid-cell:last-child {
border-right: none;
}
.grid-cell.expanded {
max-width: 500px !important;
white-space: normal !important;
overflow-wrap: break-word !important;
background-color: #e0f7fa !important;
flex: 0 0 500px !important;
}
.resizer {
width: 5px;
height: 100%;
background: #ddd;
cursor: col-resize;
position: absolute;
right: 0;
top: 0;
bottom: 0;
}
.resizer:hover {
background: #999;
}
.grid-top {
display: flex;
align-items: flex-start;
padding: 10px 0;
}
.grid-top .grid-cell {
padding: 5px 10px;
flex: 0 0 150px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.grid-top .save-all-cell {
flex: 0 0 210px;
align-items: flex-start;
}
.propagate-btn {
background: none;
border: none;
cursor: pointer;
color: #666;
font-size: 14px;
margin-top: 5px;
padding: 2px 5px;
border-radius: 3px;
transition: color 0.3s ease;
}
.propagate-btn:hover {
color: #28a745;
}
.awb-input {
width: 40% !important;
display: inline-block;
margin-right: 5px;
}
.carrier-select {
width: 40% !important;
display: inline-block;
border: 1px solid #ced4da;
border-radius: 4px;
padding: 5px;
font-size: 14px;
margin-right: 5px;
}
.go-btn {
width: 15% !important;
display: inline-block;
}
.tracking-info .tracking-result {
font-size: 12px;
color: #495057;
}
.modal {
display: none;
position: fixed;
z-index: 1050;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
#partsModal {
z-index: 1200 !important;
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 600px;
border-radius: 8px;
position: relative;
}
.close-btn {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close-btn:hover,
.close-btn:focus {
color: #000;
text-decoration: none;
}
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1049;
}
.grid-cell.missing-required {
border: 2px solid red;
background-color: #ffe6e6;
}
.dropdown-select {
width: 100%;
box-sizing: border-box;
border: 1px solid #ced4da;
border-radius: 4px;
padding: 5px;
font-size: 14px;
appearance: none;
background: white url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="%23333"><path d="M7.293 4.293a1 1 0 011.414 0L10 6.586l1.293-1.293a1 1 0 111.414 1.414l-2 2a1 1 0 01-1.414 0l-2-2a1 1 0 010-1.414z"/></svg>') no-repeat right 5px center;
}
.dropdown-select:focus {
outline: none;
border-color: #80bdff;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}
.grid-cell.button-cell,
.grid-header.button-header {
min-width: 210px !important;
flex: 0 0 210px !important;
}
.action-btn {
padding: 6px 8px;
margin-right: 5px;
border: none;
border-radius: 5px;
cursor: pointer;
width: 35px;
box-sizing: border-box;
}
.flash-success {
background-color: #d4edda !important;
transition: background-color 0.3s ease;
}
.save-all-btn {
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
padding: 8px 16px;
cursor: pointer;
font-size: 14px;
}
.save-all-btn:hover {
background-color: #218838;
}
#exportConfirmModal,
#exportResponseModal {
z-index: 1300 !important;
}
#exportConfirmModal .modal-backdrop,
#exportResponseModal .modal-backdrop {
z-index: 1299 !important;
}
</style>
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="mb-3 text">
<a href="historical_trf.php?id=<?= $template_id ?>&status=i" class="btn btn-warning me-2">Imported (i)</a>
<a href="historical_trf.php?id=<?= $template_id ?>&status=P" class="btn btn-primary me-2">In Progress (P)</a>
<a href="historical_trf.php?id=<?= $template_id ?>&status=l" class="btn btn-success">To LIMS (l)</a>
</div>
<div class="card radius-10">
<div class="card-header">
<div class="d-flex align-items-center">
<div>
<h6 class="mb-0">Modifica Dati Importati</h6>
<div id="unsavedChanges" style="display:none; color: red; font-weight: bold; margin:10px 0;">
⚠️ Unsaved changes detected! Please save before leaving this page.
<ul id="changedFields" style="margin-top:5px; font-weight:normal; color:darkred;"></ul>
</div>
</div>
</div>
</div>
<div class="card-body">
<form id="editForm">
<div class="grid-container">
<div class="grid-top">
<div class="grid-cell save-all-cell">
<button type="button" class="save-all-btn" title="Save All Rows"><i class="fas fa-save"></i> Save All</button>
</div>
<?php if ($mainFieldMapping): ?>
<div class="grid-cell" style="flex: 0 0 150px;">
<?php
$fieldValue = $mainFieldMapping['manual_default'] ?? '';
if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
$inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
if ($mainFieldMapping['data_type'] === 'SceltaMultipla') {
echo "<select class='custom-field dropdown-select $inputClass' data-column='main_field' data-field-id='{$mainFieldMapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
} elseif ($mainFieldMapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='main_field' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
} elseif ($mainFieldMapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='main_field' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='main_field' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
}
?>
</div>
<?php endif; ?>
<div class="grid-cell" style="flex: 0 0 150px;"></div>
<?php
$autoIndex = 0;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
$inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
echo "<select class='custom-field dropdown-select $inputClass' data-column='auto_$autoIndex' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex'><i class='fas fa-arrow-down'></i></button>";
echo "</div>";
} else {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
$autoIndex++;
}
}
$manualIndex = 0;
foreach ($allMappings as $mapping) {
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
$fieldValue = $mapping['manual_default'] ?? '';
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
$inputClass = 'manual-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<select class='custom-field dropdown-select $inputClass' data-column='manual_$manualIndex' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
}
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex'><i class='fas fa-arrow-down'></i></button>";
echo "</div>";
$manualIndex++;
}
}
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
?>
</div>
<div class="grid-row">
<div class="grid-header button-header" style="flex: 0 0 210px;">Actions</div>
<?php if ($mainFieldMapping): ?>
<div class="grid-header" data-index="1" style="flex: 0 0 150px; position: relative;">
<?= htmlspecialchars($mainFieldMapping['field_label']) ?>
<div class="resizer"></div>
</div>
<?php endif; ?>
<div class="grid-header" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 150px; position: relative;">Status<div class="resizer"></div>
</div>
<?php
$headerIndex = $mainFieldMapping ? 3 : 2;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
}
foreach ($allMappings as $mapping) {
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
}
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 200px; position: relative;'>AWB Number<div class='resizer'></div></div>";
$headerIndex++;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 250px; position: relative;'>Tracking Info<div class='resizer'></div></div>";
$headerIndex++;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>Import Reference Code<div class='resizer'></div></div>";
$headerIndex++;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . ($slugMapping['filename_import'] ?? 'filename_import') . "<div class='resizer'></div></div>";
$headerIndex++;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . ($slugMapping['importdate'] ?? 'importdate') . "<div class='resizer'></div></div>";
?>
</div>
<?php foreach ($importedData as $index => $row): ?>
<div class="grid-row" data-id="<?= $row['iddatadb'] ?>">
<div class="grid-cell button-cell" style="flex: 0 0 210px; position: relative;">
<button type="button" class="export-lims-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Export to LIMS" style="background: #eb0b0bff; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-upload"></i></button>
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" title="Save" style="background: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-save"></i></button>
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Photos" style="background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-camera"></i></button>
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Parts" style="background: #ffc107; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-puzzle-piece"></i></button>
</div>
<?php if ($mainFieldMapping): ?>
<?php
$detail = array_filter($manualDetails, fn($d) => $d['mapping_id'] == $mainFieldMapping['id'] && $d['datadb_id'] == $row['iddatadb']);
$detail = reset($detail) ?: ['field_value' => $mainFieldMapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mainFieldMapping['manual_default'] ?? '';
if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today' && empty($fieldValue)) {
$fieldValue = date('Y-m-d');
}
$requiredClass = ($mainFieldMapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : '';
$inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
?>
<div class="grid-cell editable-cell <?= $requiredClass ?>" data-col="main_field" data-row="<?= $index ?>" data-index="1" style="flex: 0 0 150px;">
<?php if ($mainFieldMapping['data_type'] === 'SceltaMultipla'): ?>
<select name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" class="cell-input dropdown-select <?= $inputClass ?>" data-mapping-id="<?= $mainFieldMapping['id'] ?>" data-field-id="<?= $mainFieldMapping['field_id'] ?>" data-selected-value="<?= htmlspecialchars($fieldValue) ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
<option value="">Seleziona...</option>
</select>
<?php elseif ($mainFieldMapping['data_type'] === 'DATE'): ?>
<input type="date" name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" value="<?= htmlspecialchars($fieldValue) ?>" class="cell-input <?= $inputClass ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
<?php elseif ($mainFieldMapping['data_type'] === 'INT'): ?>
<input type="number" name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" value="<?= htmlspecialchars($fieldValue) ?>" class="cell-input <?= $inputClass ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
<?php else: ?>
<input type="text" name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" value="<?= htmlspecialchars($fieldValue) ?>" class="cell-input <?= $inputClass ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="grid-cell editable-cell" data-col="status" data-row="<?= $index ?>" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 150px;">
<span class="status-badge status-<?= htmlspecialchars($row['status'] ?? 'i') ?>">
<?= htmlspecialchars($row['status'] === 'i' ? 'Imported' : ($row['status'] === 'P' ? 'In Progress' : 'To LIMS')) ?>
</span>
<input type="hidden" name="rows[<?= $index ?>][status]" value="<?= htmlspecialchars($row['status'] ?? 'i') ?>">
</div>
<?php
$cellIndex = $mainFieldMapping ? 3 : 2;
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
$autoIndex = 0;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
$detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']);
$detail = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
$requiredClass = ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : '';
$inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell editable-cell $requiredClass' data-col='auto_$autoIndex' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<select name='rows[$index][details][{$mapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mapping['id']}' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} else {
echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
}
echo "</div>";
$cellIndex++;
$autoIndex++;
}
}
$manualIndex = 0;
foreach ($allMappings as $mapping) {
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
$detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']);
$detail = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today' && empty($fieldValue)) {
$fieldValue = date('Y-m-d');
}
$requiredClass = ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : '';
$inputClass = 'manual-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell editable-cell $requiredClass' data-col='manual_$manualIndex' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<select name='rows[$index][details][{$mapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mapping['id']}' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} else {
echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
}
echo "</div>";
$cellIndex++;
$manualIndex++;
}
}
?>
<div class="grid-cell" style="flex: 0 0 200px;">
<select name="rows[<?= $index ?>][carrier]" class="carrier-select">
<option value="tnt-it">TNT Italy</option>
<option value="dhl">DHL</option>
<option value="gls">GLS</option>
<option value="sda">SDA</option>
<option value="ups">UPS</option>
</select>
<input type="text" name="rows[<?= $index ?>][awb_number]" class="cell-input awb-input" placeholder="Inserisci AWB Number">
<button type="button" class="go-btn" data-row="<?= $index ?>"><i class="fas fa-play"></i></button>
</div>
<div class="grid-cell tracking-info" data-row="<?= $index ?>" style="flex: 0 0 250px;">
<span class="tracking-result">Shipment Info</span>
<input type="hidden" name="rows[<?= $index ?>][tracking_info]" class="tracking-hidden">
</div>
<div class="grid-cell" data-col="importreferencecode" data-row="<?= $index ?>" data-index="<?= $cellIndex ?>" style="flex: 0 0 150px;">
<span><?= htmlspecialchars($row['importreferencecode']) ?></span>
<input type="hidden" name="rows[<?= $index ?>][importreferencecode]" value="<?= htmlspecialchars($row['importreferencecode']) ?>">
</div>
<?php
$cellIndex++;
?>
<div class="grid-cell editable-cell" data-col="filename_import" data-row="<?= $index ?>" data-index="<?= $cellIndex ?>" style="flex: 0 0 150px;">
<a href="imported_trf/<?= htmlspecialchars($row['filename_import']) ?>" target="_blank">File</a>
<input type="hidden" name="rows[<?= $index ?>][filename_import]" value="<?= htmlspecialchars($row['filename_import']) ?>">
</div>
<?php
$cellIndex++;
?>
<div class="grid-cell editable-cell" data-col="importdate" data-row="<?= $index ?>" data-index="<?= $cellIndex ?>" style="flex: 0 0 150px;">
<span><?= htmlspecialchars($row['importdate']) ?></span>
<input type="hidden" name="rows[<?= $index ?>][importdate]" value="<?= htmlspecialchars($row['importdate']) ?>">
</div>
</div>
<?php endforeach; ?>
</div>
</form>
<?php include 'modal_parts.php'; ?>
<?php include 'photos_functions.php'; ?>
</div>
</div>
</div>
</div>
<div class="overlay toggle-icon"></div>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<script src="photos.js"></script>
<script src="parts.js"></script>
<script src="tracking.js"></script>
<script src="export_to_lims.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("Page loaded, initializing event listeners");
const inputs = document.querySelectorAll(".cell-input, .dropdown-select, .carrier-select, .awb-input");
const unsavedDiv = document.getElementById("unsavedChanges");
const changedList = document.getElementById("changedFields");
let hasChanges = false;
let changedFields = {};
function renderChangedList() {
console.log("Rendering changed fields list:", changedFields);
changedList.innerHTML = "";
Object.keys(changedFields).forEach(rowIndex => {
const fields = changedFields[rowIndex];
if (fields.length > 0) {
const li = document.createElement("li");
li.textContent = `Row ${parseInt(rowIndex) + 1}: ${fields.join(", ")}`;
changedList.appendChild(li);
}
});
unsavedDiv.style.display = Object.keys(changedFields).length > 0 ? "block" : "none";
}
inputs.forEach(el => {
el.addEventListener("change", () => {
console.log("Input changed:", el.name);
hasChanges = true;
const gridCell = el.closest(".grid-cell");
const colIndex = gridCell?.dataset.index;
const rowIndex = gridCell?.dataset.row;
let label = "Unknown field";
if (colIndex) {
const header = document.querySelector(`.grid-header[data-index="${colIndex}"]`);
if (header) {
label = header.textContent.replace(":", "").trim();
}
}
if (rowIndex !== undefined) {
if (!changedFields[rowIndex]) {
changedFields[rowIndex] = [];
}
if (!changedFields[rowIndex].includes(label)) {
changedFields[rowIndex].push(label);
}
gridCell.classList.add("cell-changed");
}
renderChangedList();
});
});
document.querySelectorAll(".save-btn").forEach(btn => {
btn.addEventListener("click", () => {
const rowIndex = btn.dataset.row;
console.log(`Saving row ${rowIndex}`);
const row = btn.closest('.grid-row');
const iddatadb = row.getAttribute('data-id');
const formData = new FormData();
const inputs = row.querySelectorAll(`input[name^="rows[${rowIndex}][details]"], select[name^="rows[${rowIndex}][details]"]`);
inputs.forEach(input => {
const matches = input.name.match(/rows\[\d+\]\[details\]\[(\d+)\]\[field_value\]/);
if (matches) {
const mappingId = matches[1];
formData.append(`details${mappingId}field_value`, input.value);
if (input.tagName === 'SELECT' && input.classList.contains('dropdown-select')) {
input.setAttribute('data-selected-value', input.value);
}
}
});
formData.append('iddatadb', iddatadb);
fetch('save_edited_row.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
})
.then(data => {
console.log("Save response:", data);
if (data.success) {
const cells = row.querySelectorAll('.grid-cell');
cells.forEach(cell => {
cell.classList.remove('flash-success');
void cell.offsetWidth;
cell.classList.add('flash-success');
});
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
if (changedFields[rowIndex]) {
delete changedFields[rowIndex];
document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`)
.forEach(cell => cell.classList.remove("cell-changed"));
renderChangedList();
hasChanges = Object.keys(changedFields).length > 0;
}
alert('Salvataggio riga avvenuto con successo!');
} else {
alert('Errore durante il salvataggio: ' + data.message);
}
})
.catch(error => {
console.error("Save error:", error);
alert('Errore durante il salvataggio: ' + error.message);
});
});
});
document.querySelector('.save-all-btn').addEventListener('click', async () => {
console.log("Saving all rows");
const rows = document.querySelectorAll('.grid-row');
let successCount = 0;
let errorMessages = [];
for (const row of rows) {
const saveBtn = row.querySelector('.save-btn');
if (!saveBtn) {
console.warn(`No save button found in row with data-id: ${row.getAttribute('data-id')}`);
continue;
}
const rowIndex = saveBtn.dataset.row;
const iddatadb = row.getAttribute('data-id');
if (!rowIndex || !iddatadb) {
console.warn(`Missing rowIndex or iddatadb in row:`, row);
continue;
}
console.log(`Processing row ${rowIndex} with iddatadb ${iddatadb}`);
const formData = new FormData();
const inputs = row.querySelectorAll(`input[name^="rows[${rowIndex}][details]"], select[name^="rows[${rowIndex}][details]"]`);
inputs.forEach(input => {
const matches = input.name.match(/rows\[\d+\]\[details\]\[(\d+)\]\[field_value\]/);
if (matches) {
const mappingId = matches[1];
formData.append(`details${mappingId}field_value`, input.value);
if (input.tagName === 'SELECT' && input.classList.contains('dropdown-select')) {
input.setAttribute('data-selected-value', input.value);
}
}
});
formData.append('iddatadb', iddatadb);
try {
const response = await fetch('save_edited_row.php', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
console.log(`Row ${rowIndex} save response:`, data);
if (data.success) {
successCount++;
const cells = row.querySelectorAll('.grid-cell');
cells.forEach(cell => {
cell.classList.remove('flash-success');
void cell.offsetWidth;
cell.classList.add('flash-success');
});
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
if (changedFields[rowIndex]) {
delete changedFields[rowIndex];
document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`)
.forEach(cell => cell.classList.remove("cell-changed"));
}
} else {
errorMessages.push(`Riga ${parseInt(rowIndex) + 1}: ${data.message}`);
}
} catch (error) {
console.error(`Row ${rowIndex} save error:`, error);
errorMessages.push(`Riga ${parseInt(rowIndex) + 1}: ${error.message}`);
}
}
renderChangedList();
hasChanges = Object.keys(changedFields).length > 0;
console.log(`Save all completed: ${successCount} successes, ${errorMessages.length} errors`);
if (errorMessages.length === 0) {
alert(`Tutte le ${successCount} righe salvate con successo!`);
} else {
alert(`Salvate ${successCount} righe con successo.\nErrori:\n${errorMessages.join('\n')}`);
}
});
window.addEventListener("beforeunload", function(e) {
if (hasChanges) {
e.preventDefault();
e.returnValue = "";
}
});
});
// Gestisci la chiusura dei modali per rimuovere i backdrop
document.querySelectorAll('#exportConfirmModal, #exportResponseModal').forEach(modal => {
modal.addEventListener('hidden.bs.modal', () => {
console.log(`Modal ${modal.id} closed, removing backdrops`);
// Rimuovi tutti i backdrop residui
document.querySelectorAll('.modal-backdrop').forEach(backdrop => {
console.log('Removing backdrop:', backdrop);
backdrop.remove();
});
// Ripristina il body
document.body.classList.remove('modal-open');
document.body.style.paddingRight = '';
// Assicurati che l'overlay sia nascosto
const overlay = document.querySelector('.overlay.toggle-icon');
if (overlay) {
overlay.style.display = 'none';
}
});
});
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("Initializing cell expansion and propagation");
const inputs = document.querySelectorAll('.cell-input');
inputs.forEach(input => {
input.addEventListener('focus', function() {
this.closest('.grid-cell').classList.add('expanded');
});
input.addEventListener('blur', function() {
this.closest('.grid-cell').classList.remove('expanded');
});
});
const propagateButtons = document.querySelectorAll('.propagate-btn');
propagateButtons.forEach(button => {
button.addEventListener('click', function() {
console.log("Propagating value for column:", this.getAttribute('data-column'));
const column = this.getAttribute('data-column');
const input = this.previousElementSibling;
const value = input.value;
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
cell.querySelector('.propagate-btn[data-column="' + column + '"]')
);
if (targetTopIndex !== -1) {
const rows = document.querySelectorAll('.grid-row');
rows.forEach(row => {
const cells = row.querySelectorAll('.grid-cell');
if (cells.length > targetTopIndex) {
const targetInput = cells[targetTopIndex].querySelector('input, select');
if (targetInput) {
targetInput.value = value;
if (targetInput.tagName === 'SELECT') {
targetInput.setAttribute('data-selected-value', value);
const event = new Event('change');
targetInput.dispatchEvent(event);
}
}
}
});
}
});
});
const resizers = document.querySelectorAll('.resizer');
let currentResizer = null;
let startX = 0;
let startWidth = 0;
let columnIndex = 0;
resizers.forEach(resizer => {
resizer.addEventListener('mousedown', function(e) {
console.log("Starting column resize");
currentResizer = resizer;
const header = resizer.parentElement;
columnIndex = header.getAttribute('data-index');
startX = e.pageX;
startWidth = header.offsetWidth;
document.addEventListener('mousemove', resize);
document.addEventListener('mouseup', stopResize);
});
function resize(e) {
if (currentResizer) {
const dx = e.pageX - startX;
const newWidth = startWidth + dx;
const headers = document.querySelectorAll(`.grid-header[data-index="${columnIndex}"]`);
const cells = document.querySelectorAll(`.grid-cell[data-index="${columnIndex}"]`);
headers.forEach(header => header.style.flex = `0 0 ${newWidth}px`);
cells.forEach(cell => cell.style.flex = `0 0 ${newWidth}px`);
}
}
function stopResize() {
if (currentResizer) {
console.log("Stopping column resize");
document.removeEventListener('mousemove', resize);
document.removeEventListener('mouseup', stopResize);
currentResizer = null;
}
}
});
});
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("Initializing dropdown population");
const dropdownData = {};
async function populateDropdowns() {
const dropdowns = document.querySelectorAll('.dropdown-select');
if (dropdowns.length === 0) {
console.log("No dropdowns found");
return;
}
const uniqueFieldIds = [
...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))
].filter(fieldId => fieldId);
const missingFieldIds = uniqueFieldIds.filter(fieldId => !dropdownData[fieldId]);
if (missingFieldIds.length > 0) {
console.log("Fetching dropdown data for field IDs:", missingFieldIds);
try {
const response = await fetch(
`get_customfield_values.php?field_ids=${missingFieldIds.join(",")}`
);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
if (data.error) {
console.error("Fetch error:", data.error);
} else {
for (const fieldId of Object.keys(data)) {
dropdownData[fieldId] = data[fieldId] || [];
}
}
} catch (error) {
console.error("Fetch error:", error);
}
}
dropdowns.forEach(dropdown => {
const fieldId = dropdown.getAttribute('data-field-id');
const selectedValue = dropdown.getAttribute('data-selected-value') || '';
const currentValue = dropdown.value;
if (!fieldId || !dropdownData[fieldId]) {
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
console.warn(`No data for fieldId ${fieldId}`);
return;
}
dropdown.innerHTML = '<option value="">Seleziona...</option>';
dropdownData[fieldId].forEach(value => {
const option = document.createElement('option');
option.value = value.IdCustomFieldsValue;
option.textContent = value.Valore;
if (currentValue && currentValue === String(value.IdCustomFieldsValue)) {
option.selected = true;
} else if (!currentValue && selectedValue === String(value.IdCustomFieldsValue)) {
option.selected = true;
}
dropdown.appendChild(option);
});
if ((currentValue || selectedValue) && dropdown.value !== (currentValue || selectedValue)) {
dropdown.value = '';
console.warn(`Value ${currentValue || selectedValue} not found for fieldId ${fieldId}`);
}
});
}
populateDropdowns();
});
</script>
<!-- Modale di conferma per l'esportazione -->
<div class="modal fade" id="exportConfirmModal" tabindex="-1" aria-labelledby="exportConfirmModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exportConfirmModalLabel">Conferma Esportazione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p id="exportConfirmMessage">Confermi l'esportazione al LIMS per iddatadb <span id="exportIddatadb"></span>?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
<button type="button" class="btn btn-primary btn-sm" id="exportConfirmBtn">Conferma</button>
</div>
</div>
</div>
</div>
<!-- Modale di risposta per l'esportazione -->
<div class="modal fade" id="exportResponseModal" tabindex="-1" aria-labelledby="exportResponseModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exportResponseModalLabel">Risultato Esportazione</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p id="exportResponseMessage"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="modal">Chiudi</button>
</div>
</div>
</div>
</div>
</body>
</html>