change clienti to datadb and fixed column pages
This commit is contained in:
parent
a9827e4e81
commit
68c867a3f4
@ -29,7 +29,7 @@ class VisualLimsApiClient
|
|||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function authenticate()
|
private function authenticate($retryCount = 0, $maxRetries = 3)
|
||||||
{
|
{
|
||||||
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
@ -45,16 +45,22 @@ class VisualLimsApiClient
|
|||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
$log = fopen(__DIR__ . '/curl_auth_debug.log', 'w') ?: fopen('php://stderr', 'w');
|
$log = fopen(__DIR__ . '/curl_auth_debug.log', 'a') ?: fopen('php://stderr', 'w');
|
||||||
curl_setopt($ch, CURLOPT_STDERR, $log);
|
curl_setopt($ch, CURLOPT_STDERR, $log);
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
$curl_error = curl_error($ch);
|
$curl_error = curl_error($ch);
|
||||||
|
$log_message = date('Y-m-d H:i:s') . " - Auth attempt {$retryCount}: HTTP {$http_code}, Error: {$curl_error}, Response: " . substr($response, 0, 1000) . "\n";
|
||||||
|
fwrite($log, $log_message);
|
||||||
fclose($log);
|
fclose($log);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
if ($response === false || $http_code != 200) {
|
if ($response === false || $http_code != 200) {
|
||||||
|
if ($http_code === 400 && strpos($response, 'Cannot persist the object') !== false && $retryCount < $maxRetries) {
|
||||||
|
usleep(500000); // Ritardo di 500ms
|
||||||
|
return $this->authenticate($retryCount + 1, $maxRetries); // Riprova
|
||||||
|
}
|
||||||
throw new Exception("Autenticazione fallita: HTTP {$http_code}, Errore cURL: {$curl_error}, Risposta: " . substr($response, 0, 1000));
|
throw new Exception("Autenticazione fallita: HTTP {$http_code}, Errore cURL: {$curl_error}, Risposta: " . substr($response, 0, 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,5 +197,4 @@ class VisualLimsApiClient
|
|||||||
{
|
{
|
||||||
return $this->baseUrl;
|
return $this->baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,16 +23,52 @@ try {
|
|||||||
// Componi endpoint finale
|
// Componi endpoint finale
|
||||||
$endpoint = "Cliente?$queryString";
|
$endpoint = "Cliente?$queryString";
|
||||||
|
|
||||||
// Richiama API
|
// Funzione per eseguire la chiamata con retry
|
||||||
$data = $api->get($endpoint);
|
function makeApiRequest($api, $endpoint, $maxRetries = 3)
|
||||||
|
{
|
||||||
|
for ($retry = 0; $retry < $maxRetries; $retry++) {
|
||||||
|
try {
|
||||||
|
// Tenta la chiamata API
|
||||||
|
$data = $api->get($endpoint);
|
||||||
|
// Salva risposta per debug
|
||||||
|
file_put_contents(__DIR__ . '/clienti_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
return $data;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$errorMessage = $e->getMessage();
|
||||||
|
// Controlla se l'errore è legato all'autenticazione (HTTP 400 con messaggio specifico)
|
||||||
|
if (strpos($errorMessage, 'HTTP 400') !== false && strpos($errorMessage, 'Cannot persist the object') !== false) {
|
||||||
|
// Forza il refresh del token
|
||||||
|
try {
|
||||||
|
// Assumi che VisualLimsApiClient abbia un metodo per il refresh del token
|
||||||
|
$api->refreshToken(); // Da implementare in VisualLimsApiClient se non esiste
|
||||||
|
error_log("Tentativo $retry: Refresh token eseguito per endpoint $endpoint");
|
||||||
|
} catch (Exception $refreshEx) {
|
||||||
|
error_log("Errore durante il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
throw new Exception("Impossibile eseguire il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
}
|
||||||
|
// Ritarda leggermente prima del retry
|
||||||
|
usleep(500000); // 500ms
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Altri errori non gestiti dal retry
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("Massimo numero di tentativi raggiunto per $endpoint");
|
||||||
|
}
|
||||||
|
|
||||||
// Salva risposta per debug
|
// Esegui la chiamata con retry
|
||||||
file_put_contents(__DIR__ . '/clienti_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
$data = makeApiRequest($api, $endpoint);
|
||||||
|
|
||||||
echo json_encode($data);
|
echo json_encode($data);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode([
|
$errorResponse = [
|
||||||
'error' => $e->getMessage()
|
'error' => $e->getMessage(),
|
||||||
]);
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
];
|
||||||
|
error_log("Errore in get_clienti.php: " . json_encode($errorResponse));
|
||||||
|
echo json_encode($errorResponse);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,12 @@ foreach ($allMappings as $mapping) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recupera l'idclient di default dal template (se presente)
|
||||||
|
$template_stmt = $pdo->prepare("SELECT idclient FROM excel_templates WHERE id = ?");
|
||||||
|
$template_stmt->execute([$template_id]);
|
||||||
|
$template = $template_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$default_idclient = $template['idclient'] ?? null;
|
||||||
|
|
||||||
$insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids'];
|
$insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids'];
|
||||||
|
|
||||||
// Recupera i dati appena inseriti con i nomi degli utenti
|
// Recupera i dati appena inseriti con i nomi degli utenti
|
||||||
@ -410,6 +416,46 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
.flatpickr-input {
|
.flatpickr-input {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.client-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #80bdff;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-dropdown-smaller {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .select2-selection--single {
|
||||||
|
height: 31px;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||||
|
height: 31px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
@ -471,6 +517,13 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<div class="grid-cell" style="flex: 0 0 300px;">
|
||||||
|
<select class="custom-field dropdown-select client-select searchable-client" data-column="idclient" id="clientSelect" name="idclient">
|
||||||
|
<option value="">Select a client...</option>
|
||||||
|
</select>
|
||||||
|
<button type="button" class="propagate-btn" data-column="idclient"><i class="fas fa-arrow-down"></i></button>
|
||||||
|
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
|
||||||
|
</div>
|
||||||
<div class="grid-cell" style="flex: 0 0 150px;"></div>
|
<div class="grid-cell" style="flex: 0 0 150px;"></div>
|
||||||
<?php
|
<?php
|
||||||
$autoIndex = 0;
|
$autoIndex = 0;
|
||||||
@ -535,10 +588,12 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<div class="resizer"></div>
|
<div class="resizer"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<div class="grid-header" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 150px; position: relative;">Status<div class="resizer"></div>
|
<div class="grid-header" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 300px; position: relative;">Client<div class="resizer"></div>
|
||||||
|
</div>
|
||||||
|
<div class="grid-header" data-index="<?= $mainFieldMapping ? 3 : 2 ?>" style="flex: 0 0 150px; position: relative;">Status<div class="resizer"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
$headerIndex = $mainFieldMapping ? 3 : 2;
|
$headerIndex = $mainFieldMapping ? 4 : 3;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if (!$mapping['is_manual'] && $mapping['main_field'] != 1 && $mapping['is_visible_import'] == 1) {
|
if (!$mapping['is_manual'] && $mapping['main_field'] != 1 && $mapping['is_visible_import'] == 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>";
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
|
||||||
@ -604,14 +659,19 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<div class="grid-cell editable-cell" data-col="status" data-row="<?= $index ?>" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 150px;">
|
<div class="grid-cell editable-cell" data-col="idclient" data-row="<?= $index ?>" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 300px;">
|
||||||
|
<select name="rows[<?= $index ?>][idclient]" class="cell-input dropdown-select client-select searchable-client" data-current-value="<?= htmlspecialchars($row['idclient'] ?? $default_idclient) ?>">
|
||||||
|
<option value="">Select a client...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="grid-cell editable-cell" data-col="status" data-row="<?= $index ?>" data-index="<?= $mainFieldMapping ? 3 : 2 ?>" style="flex: 0 0 150px;">
|
||||||
<span class="status-badge status-<?= htmlspecialchars($row['status'] ?? 'i') ?>">
|
<span class="status-badge status-<?= htmlspecialchars($row['status'] ?? 'i') ?>">
|
||||||
<?= htmlspecialchars($row['status'] === 'i' ? 'Imported' : ($row['status'] === 'P' ? 'In Progress' : 'To LIMS')) ?>
|
<?= htmlspecialchars($row['status'] === 'i' ? 'Imported' : ($row['status'] === 'P' ? 'In Progress' : 'To LIMS')) ?>
|
||||||
</span>
|
</span>
|
||||||
<input type="hidden" name="rows[<?= $index ?>][status]" value="<?= htmlspecialchars($row['status'] ?? 'i') ?>">
|
<input type="hidden" name="rows[<?= $index ?>][status]" value="<?= htmlspecialchars($row['status'] ?? 'i') ?>">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
$cellIndex = $mainFieldMapping ? 3 : 2;
|
$cellIndex = $mainFieldMapping ? 4 : 3;
|
||||||
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
|
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
|
||||||
$autoIndex = 0;
|
$autoIndex = 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
@ -840,11 +900,16 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
if (matches) {
|
if (matches) {
|
||||||
const mappingId = matches[1];
|
const mappingId = matches[1];
|
||||||
formData.append(`details${mappingId}field_value`, input.value);
|
formData.append(`details${mappingId}field_value`, input.value);
|
||||||
if (input.tagName === 'SELECT' && input.classList.contains('dropdown-select')) {
|
if (input.tagName === 'SELECT') {
|
||||||
input.setAttribute('data-selected-value', input.value);
|
input.setAttribute('data-selected-value', input.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const idclientSelect = row.querySelector(`select[name="rows[${rowIndex}][idclient]"]`);
|
||||||
|
if (idclientSelect) {
|
||||||
|
formData.append('idclient', idclientSelect.value);
|
||||||
|
}
|
||||||
formData.append('iddatadb', iddatadb);
|
formData.append('iddatadb', iddatadb);
|
||||||
|
|
||||||
fetch('save_edited_row.php', {
|
fetch('save_edited_row.php', {
|
||||||
@ -912,6 +977,11 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const idclientSelect = row.querySelector(`select[name="rows[${rowIndex}][idclient]"]`);
|
||||||
|
if (idclientSelect) {
|
||||||
|
formData.append('idclient', idclientSelect.value);
|
||||||
|
}
|
||||||
formData.append('iddatadb', iddatadb);
|
formData.append('iddatadb', iddatadb);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -984,6 +1054,90 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
const inputs = document.querySelectorAll('.cell-input');
|
const inputs = document.querySelectorAll('.cell-input');
|
||||||
|
let clientData = []; // Dichiarazione di clientData qui
|
||||||
|
|
||||||
|
// Funzione per caricare i client
|
||||||
|
async function loadClients(retryCount = 0, maxRetries = 3) {
|
||||||
|
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
|
||||||
|
try {
|
||||||
|
clientLoadingStatus.style.display = 'inline';
|
||||||
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
const response = await fetch("get_clienti.php", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (!response.ok) {
|
||||||
|
if (response.status === 500 && data.error.includes('Cannot persist the object') && retryCount < maxRetries) {
|
||||||
|
console.log(`Tentativo ${retryCount + 1}/${maxRetries}: Riprovo a caricare i clienti...`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
return loadClients(retryCount + 1, maxRetries);
|
||||||
|
}
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
clientData = data.value || [];
|
||||||
|
const select = document.getElementById("clientSelect");
|
||||||
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
clientData.forEach(client => {
|
||||||
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
|
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
select.add(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
populateClientDropdowns();
|
||||||
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
|
} catch (error) {
|
||||||
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
console.error("Errore nel caricamento dei client:", error);
|
||||||
|
Swal.fire({
|
||||||
|
title: "Errore!",
|
||||||
|
text: "Impossibile caricare i clienti: " + error.message,
|
||||||
|
icon: "error",
|
||||||
|
confirmButtonText: "OK"
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Funzione per popolare i dropdown dei client
|
||||||
|
function populateClientDropdowns() {
|
||||||
|
const clientDropdowns = document.querySelectorAll('select[name^="rows"][name$="[idclient]"]');
|
||||||
|
clientDropdowns.forEach(dropdown => {
|
||||||
|
const currentValue = dropdown.getAttribute('data-current-value') || '';
|
||||||
|
dropdown.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
clientData.forEach(client => {
|
||||||
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
|
if (String(id) === String(currentValue)) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
dropdown.add(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ripristina il valore corrente
|
||||||
|
if (currentValue) {
|
||||||
|
dropdown.value = currentValue;
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
dropdown.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carica i client all'avvio
|
||||||
|
loadClients();
|
||||||
|
|
||||||
|
// Gestione degli input
|
||||||
inputs.forEach(input => {
|
inputs.forEach(input => {
|
||||||
input.addEventListener('focus', function() {
|
input.addEventListener('focus', function() {
|
||||||
this.closest('.grid-cell').classList.add('expanded');
|
this.closest('.grid-cell').classList.add('expanded');
|
||||||
@ -993,42 +1147,60 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Gestione della propagazione
|
||||||
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
||||||
propagateButtons.forEach(button => {
|
propagateButtons.forEach(button => {
|
||||||
button.addEventListener('click', function() {
|
button.addEventListener('click', async function() {
|
||||||
const column = this.getAttribute('data-column');
|
const column = this.getAttribute('data-column');
|
||||||
const input = this.previousElementSibling;
|
const input = this.previousElementSibling;
|
||||||
const value = input.value;
|
const value = input.tagName === 'SELECT' ? input.value : input.value;
|
||||||
|
|
||||||
|
console.log('Propagate clicked for column:', column, 'with value:', value); // Debug
|
||||||
|
|
||||||
|
// Assicurati che i dropdown dei client siano popolati
|
||||||
|
if (column === 'idclient' && clientData.length === 0) {
|
||||||
|
await loadClients(); // Carica i client se non ancora caricati
|
||||||
|
}
|
||||||
|
|
||||||
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
||||||
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
||||||
cell.querySelector('.propagate-btn[data-column="' + column + '"]')
|
cell.querySelector('.propagate-btn[data-column="' + column + '"]')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('Target index found:', targetTopIndex); // Debug
|
||||||
|
|
||||||
if (targetTopIndex !== -1) {
|
if (targetTopIndex !== -1) {
|
||||||
const rows = document.querySelectorAll('.grid-row');
|
const rows = document.querySelectorAll('.grid-row');
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
const cells = row.querySelectorAll('.grid-cell');
|
const cells = row.querySelectorAll('.grid-cell');
|
||||||
if (cells.length > targetTopIndex) {
|
if (cells.length > targetTopIndex) {
|
||||||
const targetInput = cells[targetTopIndex].querySelector('input, select');
|
const targetInput = cells[targetTopIndex].querySelector('select, input');
|
||||||
if (targetInput) {
|
if (targetInput) {
|
||||||
targetInput.value = value;
|
console.log('Setting value on target input:', targetInput, 'with value:', value); // Debug
|
||||||
if (targetInput.tagName === 'SELECT') {
|
if (targetInput.tagName === 'SELECT') {
|
||||||
targetInput.setAttribute('data-selected-value', value);
|
targetInput.value = value;
|
||||||
const event = new Event('change');
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
targetInput.dispatchEvent(event);
|
targetInput.dispatchEvent(event);
|
||||||
} else if (targetInput.classList.contains('date-picker')) {
|
} else if (targetInput.classList.contains('date-picker')) {
|
||||||
// Update Flatpickr instance
|
|
||||||
const flatpickrInstance = targetInput._flatpickr;
|
const flatpickrInstance = targetInput._flatpickr;
|
||||||
if (flatpickrInstance && value) {
|
if (flatpickrInstance && value) {
|
||||||
flatpickrInstance.setDate(value, true);
|
flatpickrInstance.setDate(value, true);
|
||||||
}
|
}
|
||||||
const event = new Event('change');
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
targetInput.dispatchEvent(event);
|
targetInput.dispatchEvent(event);
|
||||||
} else {
|
} else {
|
||||||
const event = new Event('change');
|
targetInput.value = value;
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
targetInput.dispatchEvent(event);
|
targetInput.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('No target input found in cell'); // Debug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1036,6 +1208,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Gestione del ridimensionamento delle colonne
|
||||||
const resizers = document.querySelectorAll('.resizer');
|
const resizers = document.querySelectorAll('.resizer');
|
||||||
let currentResizer = null;
|
let currentResizer = null;
|
||||||
let startX = 0;
|
let startX = 0;
|
||||||
@ -1078,7 +1251,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
const dropdownData = {};
|
const dropdownData = {};
|
||||||
|
|
||||||
async function populateDropdowns() {
|
async function populateDropdowns() {
|
||||||
const dropdowns = document.querySelectorAll('.dropdown-select');
|
const dropdowns = document.querySelectorAll('.dropdown-select:not(.client-select)');
|
||||||
if (dropdowns.length === 0) {
|
if (dropdowns.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1102,13 +1275,15 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
dropdownData[fieldId] = data[fieldId] || [];
|
dropdownData[fieldId] = data[fieldId] || [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
console.error('Errore nel caricamento dei valori per dropdown:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dropdowns.forEach(dropdown => {
|
dropdowns.forEach(dropdown => {
|
||||||
const fieldId = dropdown.getAttribute('data-field-id');
|
const fieldId = dropdown.getAttribute('data-field-id');
|
||||||
const selectedValue = dropdown.getAttribute('data-selected-value') || '';
|
const selectedValue = dropdown.getAttribute('data-selected-value') || '';
|
||||||
const currentValue = dropdown.value;
|
const currentValue = dropdown.value || '';
|
||||||
|
|
||||||
if (!fieldId || !dropdownData[fieldId]) {
|
if (!fieldId || !dropdownData[fieldId]) {
|
||||||
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
||||||
@ -1128,63 +1303,178 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
dropdown.appendChild(option);
|
dropdown.appendChild(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
if ((currentValue || selectedValue) && dropdown.value !== (currentValue || selectedValue)) {
|
// Ripristina il valore corrente
|
||||||
dropdown.value = '';
|
if (currentValue || selectedValue) {
|
||||||
|
dropdown.value = currentValue || selectedValue;
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
dropdown.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
populateDropdowns();
|
populateDropdowns();
|
||||||
});
|
});
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
$(document).on('click', '.add-part-btn', function() {
|
|
||||||
const rowIndex = $(this).data('row');
|
|
||||||
const row = $(this).closest('.grid-row');
|
|
||||||
const iddatadb = row.data('id');
|
|
||||||
const input = row.find(`input[name="rows[${rowIndex}][tested_component]"]`);
|
|
||||||
const description = input.val().trim();
|
|
||||||
|
|
||||||
if (!description) {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
alert('Inserisci un valore per Tested Component');
|
let clientData = [];
|
||||||
return;
|
|
||||||
|
async function loadClients(retryCount = 0, maxRetries = 3) {
|
||||||
|
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
|
||||||
|
try {
|
||||||
|
clientLoadingStatus.style.display = 'inline';
|
||||||
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
const response = await fetch("get_clienti.php", {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (!response.ok) {
|
||||||
|
if (response.status === 500 && data.error.includes('Cannot persist the object') && retryCount < maxRetries) {
|
||||||
|
console.log(`Tentativo ${retryCount + 1}/${maxRetries}: Riprovo a caricare i clienti...`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
return loadClients(retryCount + 1, maxRetries);
|
||||||
|
}
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
clientData = data.value || [];
|
||||||
|
const select = document.getElementById("clientSelect");
|
||||||
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
clientData.forEach(client => {
|
||||||
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
|
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
select.add(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
populateClientDropdowns();
|
||||||
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
|
} catch (error) {
|
||||||
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
Swal.fire({
|
||||||
|
title: "Errore!",
|
||||||
|
text: "Impossibile caricare i clienti: " + error.message,
|
||||||
|
icon: "error",
|
||||||
|
confirmButtonText: "OK"
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
function populateClientDropdowns() {
|
||||||
iddatadb: iddatadb,
|
const clientDropdowns = document.querySelectorAll('select[name^="rows"][name$="[idclient]"]');
|
||||||
parts: [{
|
clientDropdowns.forEach(dropdown => {
|
||||||
part_number: '1', // Imposta part_number a '1'
|
const currentValue = dropdown.getAttribute('data-current-value') || '';
|
||||||
part_description: description,
|
dropdown.innerHTML = '<option value="">Select a client...</option>';
|
||||||
mix: 'N'
|
clientData.forEach(client => {
|
||||||
}]
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
};
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
$.ajax({
|
if (String(id) === String(currentValue)) {
|
||||||
url: 'save_parts.php',
|
option.selected = true;
|
||||||
method: 'POST',
|
|
||||||
contentType: 'application/json',
|
|
||||||
data: JSON.stringify(data),
|
|
||||||
success: function(response) {
|
|
||||||
if (response.success) {
|
|
||||||
alert('Parte aggiunta con successo!');
|
|
||||||
input.val(''); // Pulisci l'input dopo l'aggiunta
|
|
||||||
// Opzionale: aggiorna la tabella delle parti se il modal è aperto
|
|
||||||
const partsModal = $('#partsModal');
|
|
||||||
if (partsModal.hasClass('show')) {
|
|
||||||
loadParts(iddatadb);
|
|
||||||
}
|
}
|
||||||
} else {
|
dropdown.add(option);
|
||||||
alert('Errore: ' + response.message);
|
});
|
||||||
|
|
||||||
|
// Ripristina il valore corrente
|
||||||
|
if (currentValue) {
|
||||||
|
dropdown.value = currentValue;
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
dropdown.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
error: function() {
|
}
|
||||||
alert('Errore durante la richiesta AJAX');
|
|
||||||
|
loadClients();
|
||||||
|
|
||||||
|
document.getElementById('clientSelect').addEventListener('change', function() {
|
||||||
|
const gridCell = this.closest('.grid-cell');
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
gridCell.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('change', function(e) {
|
||||||
|
if (e.target.matches('select[name^="rows"][name$="[idclient]"]')) {
|
||||||
|
const gridCell = e.target.closest('.grid-cell');
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
gridCell.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
// Gestione del cambio valore per il dropdown principale dei client
|
||||||
|
document.getElementById('clientSelect').addEventListener('change', function() {
|
||||||
|
const gridCell = this.closest('.grid-cell');
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
gridCell.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gestione del cambio valore per i dropdown dei client nelle righe
|
||||||
|
document.addEventListener('change', function(e) {
|
||||||
|
if (e.target.matches('select[name^="rows"][name$="[idclient]"]')) {
|
||||||
|
const gridCell = e.target.closest('.grid-cell');
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
gridCell.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
// Initialize Select2 for searchable client dropdowns
|
||||||
|
$('.searchable-client').select2({
|
||||||
|
placeholder: "Select a client...",
|
||||||
|
allowClear: true,
|
||||||
|
width: '100%',
|
||||||
|
dropdownCssClass: 'select2-dropdown-smaller',
|
||||||
|
minimumInputLength: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure Select2 dropdowns trigger change events for unsaved changes tracking
|
||||||
|
$('.searchable-client').on('select2:select select2:clear', function(e) {
|
||||||
|
const gridCell = this.closest('.grid-cell');
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
gridCell.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update propagate functionality for client dropdown
|
||||||
|
$('.propagate-btn[data-column="idclient"]').on('click', async function() {
|
||||||
|
const value = $('#clientSelect').val();
|
||||||
|
const rows = document.querySelectorAll('.grid-row');
|
||||||
|
rows.forEach(row => {
|
||||||
|
const clientSelect = row.querySelector('select[name$="[idclient]"]');
|
||||||
|
if (clientSelect) {
|
||||||
|
$(clientSelect).val(value).trigger('change.select2');
|
||||||
|
const event = new Event('change', {
|
||||||
|
bubbles: true
|
||||||
|
});
|
||||||
|
clientSelect.closest('.grid-cell').dispatchEvent(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$(document).on('click', '.parts-btn', function() {
|
$(document).on('click', '.parts-btn', function() {
|
||||||
const iddatadb = $(this).data('iddatadb') || null;
|
const iddatadb = $(this).data('iddatadb') || null;
|
||||||
const idquotations = $(this).data('idquotations') || null;
|
const idquotations = $(this).data('idquotations') || null;
|
||||||
|
|||||||
@ -75,6 +75,12 @@ foreach ($selected_rows as $rowIndex) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recupera l'idclient di default dal template
|
||||||
|
$template_stmt = $pdo->prepare("SELECT idclient FROM excel_templates WHERE id = ?");
|
||||||
|
$template_stmt->execute([$template_id]);
|
||||||
|
$template = $template_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$default_idclient = $template['idclient'] ?? null;
|
||||||
|
|
||||||
$values = [
|
$values = [
|
||||||
$template_id,
|
$template_id,
|
||||||
$importReferenceCode,
|
$importReferenceCode,
|
||||||
@ -83,9 +89,10 @@ foreach ($selected_rows as $rowIndex) {
|
|||||||
$user_id,
|
$user_id,
|
||||||
null,
|
null,
|
||||||
date('Y-m-d'),
|
date('Y-m-d'),
|
||||||
$excelrow // Aggiunto excelrow per la colonna excelrow
|
$excelrow,
|
||||||
|
$default_idclient // Aggiungi idclient
|
||||||
];
|
];
|
||||||
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate, excelrow) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate, excelrow, idclient) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
$stmt = $pdo->prepare($sql);
|
$stmt = $pdo->prepare($sql);
|
||||||
$stmt->execute($values);
|
$stmt->execute($values);
|
||||||
|
|
||||||
|
|||||||
@ -108,7 +108,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recupera routine dal template
|
// Recupera routine dal template
|
||||||
$stmt = $pdo->prepare("SELECT idroutine FROM excel_templates WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT idroutine, idclient FROM excel_templates WHERE id = ?");
|
||||||
$stmt->execute([$template_id]);
|
$stmt->execute([$template_id]);
|
||||||
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
@ -133,6 +133,9 @@ try {
|
|||||||
error_log("Nessuna routine associata al template {$template_id}");
|
error_log("Nessuna routine associata al template {$template_id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aggiungi idclient alla risposta
|
||||||
|
$response['idclient'] = $template['idclient'] ?? null;
|
||||||
|
|
||||||
// Salva i dati in sessione
|
// Salva i dati in sessione
|
||||||
$_SESSION['excel_data'] = $excelData;
|
$_SESSION['excel_data'] = $excelData;
|
||||||
$_SESSION['template_id'] = $template_id;
|
$_SESSION['template_id'] = $template_id;
|
||||||
|
|||||||
@ -11,13 +11,14 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$iddatadb = intval($_POST['iddatadb']);
|
$iddatadb = intval($_POST['iddatadb']);
|
||||||
|
$idclient = isset($_POST['idclient']) ? (is_numeric($_POST['idclient']) ? intval($_POST['idclient']) : null) : null;
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
$data = $_POST;
|
$data = $_POST;
|
||||||
$details = [];
|
$details = [];
|
||||||
|
|
||||||
// 1. POST-დან ამოვიღოთ მხოლოდ details
|
// 1. Estrarre i dettagli da POST
|
||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
if (preg_match('/^details(\d+)field_value$/', $key, $matches)) {
|
if (preg_match('/^details(\d+)field_value$/', $key, $matches)) {
|
||||||
$id = $matches[1];
|
$id = $matches[1];
|
||||||
@ -25,16 +26,15 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. DB-დან წამოვიღოთ არსებული მნიშვნელობები
|
// 2. Recupera i valori esistenti da import_data_details
|
||||||
$stmt = $pdo->prepare("SELECT mapping_id, field_value FROM import_data_details WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT mapping_id, field_value FROM import_data_details WHERE id = ?");
|
||||||
$stmt->execute([$iddatadb]);
|
$stmt->execute([$iddatadb]);
|
||||||
|
|
||||||
$currentValues = [];
|
$currentValues = [];
|
||||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$currentValues[$row['mapping_id']] = $row['field_value'];
|
$currentValues[$row['mapping_id']] = $row['field_value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. შევადაროთ POST-ს და DB-ს
|
// 3. Confronta i valori nuovi con quelli esistenti
|
||||||
$changed = [];
|
$changed = [];
|
||||||
foreach ($details as $id => $newValue) {
|
foreach ($details as $id => $newValue) {
|
||||||
$oldValue = $currentValues[$id] ?? null;
|
$oldValue = $currentValues[$id] ?? null;
|
||||||
@ -46,7 +46,7 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. თუ არის ცვლილებები → UPDATE
|
// 4. Aggiorna i dettagli se ci sono modifiche
|
||||||
if (!empty($changed)) {
|
if (!empty($changed)) {
|
||||||
$updateStmt = $pdo->prepare("
|
$updateStmt = $pdo->prepare("
|
||||||
UPDATE import_data_details
|
UPDATE import_data_details
|
||||||
@ -61,15 +61,27 @@ try {
|
|||||||
':mappingId' => $mappingId
|
':mappingId' => $mappingId
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response['success'] = true;
|
|
||||||
$response['message'] = "Updated successfully";
|
|
||||||
$response['changed'] = $changed; // Debug / optional
|
|
||||||
} else {
|
|
||||||
$response['success'] = true;
|
|
||||||
$response['message'] = "No changes found";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Aggiorna idclient in datadb
|
||||||
|
if (isset($idclient)) {
|
||||||
|
$updateStmt = $pdo->prepare("
|
||||||
|
UPDATE datadb
|
||||||
|
SET idclient = :idclient
|
||||||
|
WHERE iddatadb = :iddatadb
|
||||||
|
");
|
||||||
|
$updateStmt->execute([
|
||||||
|
':idclient' => $idclient,
|
||||||
|
':iddatadb' => $iddatadb
|
||||||
|
]);
|
||||||
|
$response['message'] = !empty($changed) ? "Updated details and idclient successfully" : "Updated idclient successfully";
|
||||||
|
} else {
|
||||||
|
$response['message'] = !empty($changed) ? "Updated details successfully" : "No changes found";
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['success'] = true;
|
||||||
|
$response['changed'] = $changed; // Debug / optional
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$response['success'] = false;
|
$response['success'] = false;
|
||||||
$response['message'] = $e->getMessage();
|
$response['message'] = $e->getMessage();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user