getConnection(); // Genera un UUID univoco per importreferencecode $importReferenceCode = date('YmdHis') . '-' . uniqid(); // Recupera tutti i mapping dal template $stmt = $pdo->prepare(" SELECT id, excel_column, json_node, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field, auto_value, has_list 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; } } // Inserisci le righe selezionate in datadb $insertedIds = []; // Binding JSON -> LIMS senza corrispondenza salvata, per "mapping_id|json_value". $pendingBindings = []; // Binding risolti in automatico durante questo import (solo per visualizzazione). $autoBindings = []; // Binding gia' salvati in precedenza, usati su questo import (visualizzazione + modifica). $savedBindings = []; foreach ($selected_rows as $loopIndex => $rowIndex) { if ($source_type === 'json') { // JSON import sends only selected rows in rows/excelrows $row = $rows[$loopIndex] ?? null; $excelrow = $excelrows[$loopIndex] ?? ('JSON-' . ($loopIndex + 1)); } else { // XLS import keeps original row indexes $row = $rows[$rowIndex] ?? null; $excelrow = $excelrows[$rowIndex] ?? null; } if ($row === null || $excelrow === null) { error_log("Errore: riga o excelrow mancante. Source type: $source_type, loopIndex: $loopIndex, rowIndex: $rowIndex"); 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; // excelrow e' INT: dal JSON arriva tipo 'JSON-1', tengo solo la parte numerica. if (is_numeric($excelrow)) { $excelrowDb = (int) $excelrow; } else { $digits = preg_replace('/\D+/', '', (string) $excelrow); $excelrowDb = $digits !== '' ? (int) $digits : ($loopIndex + 1); } $values = [ $template_id, $importReferenceCode, $newFilename, 'i', $user_id, null, date('Y-m-d'), $excelrowDb, $default_idclient // Aggiungi idclient ]; $sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate, excelrow, idclient) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = $pdo->prepare($sql); $stmt->execute($values); $iddatadb = $pdo->lastInsertId(); $insertedIds[] = $iddatadb; // Inserisci tutti i campi in import_data_details foreach ($allMappings as $mapping) { $fieldValue = null; if (!$mapping['is_manual']) { $sourceColumn = ''; if ($source_type === 'json') { $sourceColumn = trim($mapping['json_node'] ?? ''); } else { $sourceColumn = trim($mapping['excel_column'] ?? ''); } // Fallback: if JSON node is empty, try excel_column if ($sourceColumn === '') { $sourceColumn = trim($mapping['excel_column'] ?? ''); } $columnsTrimmed = array_map('trim', $columns); $candidateColumns = []; if ($sourceColumn !== '') { $candidateColumns[] = $sourceColumn; if ($source_type === 'json') { // Common JSON path variants $candidateColumns[] = preg_replace('/^data\[\]\./', '', $sourceColumn); $candidateColumns[] = preg_replace('/^data\.0\./', '', $sourceColumn); $candidateColumns[] = str_replace('data[].', 'data.0.', $sourceColumn); $candidateColumns[] = str_replace('data.0.', 'data[].', $sourceColumn); } } // Remove empty and duplicate candidates $candidateColumns = array_values(array_unique(array_filter($candidateColumns, function ($value) { return trim((string)$value) !== ''; }))); $sourceColumnIndex = false; $matchedColumn = ''; foreach ($candidateColumns as $candidateColumn) { $candidateColumn = trim($candidateColumn); $index = array_search($candidateColumn, $columnsTrimmed); if ($index !== false) { $sourceColumnIndex = $index; $matchedColumn = $candidateColumn; break; } } if ($sourceColumnIndex !== false && isset($row[$sourceColumnIndex]) && $row[$sourceColumnIndex] !== '') { $fieldValue = $row[$sourceColumnIndex]; error_log( "Found source column. Original: '$sourceColumn', Matched: '$matchedColumn', Index: $sourceColumnIndex, Value: " . var_export($fieldValue, true) ); } else { $fieldValue = $mapping['manual_default'] ?? ''; error_log( "Source column not found or empty. Original: '$sourceColumn'. Candidates: " . json_encode($candidateColumns) . ". Available columns: " . json_encode($columnsTrimmed) . ". Using default: " . var_export($fieldValue, true) ); } switch ($mapping['data_type']) { case 'INT': $fieldValue = is_numeric($fieldValue) ? (int)$fieldValue : ($mapping['manual_default'] ?? 0); break; case 'DATE': $fieldValue = !empty($fieldValue) ? date('Y-m-d', strtotime($fieldValue)) : ($mapping['manual_default'] === 'today' ? date('Y-m-d') : ($mapping['manual_default'] ?? '')); break; case 'CHAR': $fieldValue = !empty($fieldValue) ? substr((string)$fieldValue, 0, 1) : ($mapping['manual_default'] ?? ''); break; case 'Testo': case 'VARCHAR': default: $fieldValue = !empty($fieldValue) ? (string)$fieldValue : ($mapping['manual_default'] ?? ''); break; } } else { $fieldValue = $mapping['manual_default'] ?? ''; if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') { $fieldValue = date('Y-m-d'); } } // Apply auto_value if field is still empty if (($fieldValue === null || $fieldValue === '') && !empty($mapping['auto_value']) && $mapping['auto_value'] !== 'none') { if ($mapping['auto_value'] === 'import_date') { $fieldValue = date('Y-m-d'); } elseif ($mapping['auto_value'] === 'import_time') { $fieldValue = date('H:i'); } } // Binding JSON -> LIMS solo per i campi a lista importati da JSON. if ( $source_type === 'json' && !$mapping['is_manual'] && binding_is_list_field($mapping) && $fieldValue !== null && $fieldValue !== '' ) { $jsonValue = (string) $fieldValue; $existing = binding_lookup($pdo, (int) $mapping['id'], $jsonValue); if ($existing) { $fieldValue = $existing['lims_value']; $key = $mapping['id'] . '|' . $jsonValue; if (!isset($savedBindings[$key])) { $savedBindings[$key] = [ 'mapping_id' => (int) $mapping['id'], 'field_id' => (int) $mapping['field_id'], 'field_label' => $mapping['field_label'], 'json_value' => $jsonValue, 'lims_value' => (string) $existing['lims_value'], 'lims_value_id' => (int) $existing['lims_value_id'], 'datadb_ids' => [], ]; } $savedBindings[$key]['datadb_ids'][] = (int) $iddatadb; } else { // Nessun binding salvato: provo l'auto-match 1-a-1 sui valori LIMS. $limsValues = binding_get_lims_values((int) $mapping['field_id']); $autoMatch = binding_auto_match($limsValues, $jsonValue); if ($autoMatch) { binding_upsert( $pdo, (int) $template_id, (int) $mapping['id'], (int) $mapping['field_id'], $jsonValue, (int) $autoMatch['IdCustomFieldsValue'], (string) $autoMatch['Valore'], $user_id ); $fieldValue = (string) $autoMatch['Valore']; $key = $mapping['id'] . '|' . $jsonValue; if (!isset($autoBindings[$key])) { $autoBindings[$key] = [ 'mapping_id' => (int) $mapping['id'], 'field_id' => (int) $mapping['field_id'], 'field_label' => $mapping['field_label'], 'json_value' => $jsonValue, 'lims_value' => (string) $autoMatch['Valore'], 'lims_value_id' => (int) $autoMatch['IdCustomFieldsValue'], 'datadb_ids' => [], ]; } $autoBindings[$key]['datadb_ids'][] = (int) $iddatadb; } else { $key = $mapping['id'] . '|' . $jsonValue; if (!isset($pendingBindings[$key])) { $pendingBindings[$key] = [ 'mapping_id' => (int) $mapping['id'], 'field_id' => (int) $mapping['field_id'], 'field_label' => $mapping['field_label'], 'json_value' => $jsonValue, 'datadb_ids' => [], ]; } $pendingBindings[$key]['datadb_ids'][] = (int) $iddatadb; } } } if ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) { error_log("Required field missing for mapping ID: " . $mapping['id'] . ", field: " . $mapping['field_label']); } error_log("Inserting into import_data_details - Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true) . ", Is Manual: " . $mapping['is_manual'] . ", Source Column: " . ($sourceColumn ?? 'N/A') . ", Source Type: " . $source_type . ", Manual Default: " . ($mapping['manual_default'] ?? 'N/A')); $stmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)"); $stmt->execute([$iddatadb, $mapping['id'], $fieldValue]); error_log("Inserted into import_data_details for ID $iddatadb, Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true)); } } $_SESSION['inserted_ids'] = $insertedIds; $importedUrl = "imported.php?id=" . urlencode($template_id) . "&importref=" . urlencode($importReferenceCode); // Solo se restano binding da risolvere mostro la pagina (con anche gli auto, modificabili). if (!empty($pendingBindings)) { $_SESSION['pending_bindings'] = [ 'template_id' => $template_id, 'importref' => $importReferenceCode, 'items' => array_values($pendingBindings), 'auto' => array_values($autoBindings), 'saved' => array_values($savedBindings), ]; header("Location: resolve_bindings.php"); exit; } unset($_SESSION['pending_bindings']); // Solo auto-collegati: vado diretto alla griglia, segnalando quanti. if (!empty($autoBindings)) { $importedUrl .= "&autobound=" . count($autoBindings); } header("Location: " . $importedUrl); exit;