json bindings
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
include('include/headscript.php');
|
||||
|
||||
$db = DBHandlerSelect::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
|
||||
// Filtro opzionale per template.
|
||||
$templateFilter = isset($_GET['template_id']) ? intval($_GET['template_id']) : 0;
|
||||
|
||||
$templates = $pdo->query("SELECT id, name FROM excel_templates ORDER BY name")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$where = '';
|
||||
$params = [];
|
||||
if ($templateFilter > 0) {
|
||||
$where = 'WHERE b.template_id = ?';
|
||||
$params[] = $templateFilter;
|
||||
}
|
||||
|
||||
$sql = "SELECT b.id, b.template_id, b.mapping_id, b.field_id, b.json_value,
|
||||
b.lims_value_id, b.lims_value, b.updated_at,
|
||||
t.name AS template_name,
|
||||
m.field_label
|
||||
FROM json_lims_binding b
|
||||
LEFT JOIN excel_templates t ON t.id = b.template_id
|
||||
LEFT JOIN template_mapping m ON m.id = b.mapping_id
|
||||
$where
|
||||
ORDER BY t.name, m.field_label, b.json_value";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$bindings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
<!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 href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.json-value {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
td .select2-container {
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.row-status {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
<title>Gestione Binding JSON -> LIMS - <?= 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="card radius-10">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2">
|
||||
<h6 class="mb-0">Gestione Binding JSON -> LIMS</h6>
|
||||
<form method="GET" class="d-flex align-items-center gap-2">
|
||||
<label class="small text-muted mb-0">Template</label>
|
||||
<select name="template_id" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||
<option value="0">Tutti</option>
|
||||
<?php foreach ($templates as $t): ?>
|
||||
<option value="<?= (int) $t['id'] ?>" <?= $templateFilter === (int) $t['id'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($t['name']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div id="globalError" class="alert alert-danger" style="display:none;"></div>
|
||||
|
||||
<div class="alert alert-secondary small">
|
||||
Le modifiche ai binding si applicano alle <strong>importazioni future</strong>.
|
||||
I record gia' importati non vengono ricalcolati.
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Template</th>
|
||||
<th>Campo (template_mapping)</th>
|
||||
<th>Valore JSON</th>
|
||||
<th>Valore LIMS</th>
|
||||
<th style="width:170px;">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($bindings)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted">Nessun binding presente.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($bindings as $b): ?>
|
||||
<tr data-id="<?= (int) $b['id'] ?>"
|
||||
data-mapping-id="<?= (int) $b['mapping_id'] ?>"
|
||||
data-field-id="<?= (int) $b['field_id'] ?>"
|
||||
data-template-id="<?= (int) $b['template_id'] ?>"
|
||||
data-json-value="<?= htmlspecialchars($b['json_value'], ENT_QUOTES) ?>">
|
||||
<td><?= htmlspecialchars($b['template_name'] ?? ('#' . $b['template_id'])) ?></td>
|
||||
<td><?= htmlspecialchars($b['field_label'] ?? ('mapping ' . $b['mapping_id'])) ?></td>
|
||||
<td class="json-value"><?= htmlspecialchars($b['json_value']) ?></td>
|
||||
<td>
|
||||
<select class="form-select binding-select" data-field-id="<?= (int) $b['field_id'] ?>">
|
||||
<?php if ($b['lims_value_id']): ?>
|
||||
<option value="<?= (int) $b['lims_value_id'] ?>" selected>
|
||||
<?= htmlspecialchars($b['lims_value']) ?>
|
||||
</option>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
<span class="row-status text-muted"></span>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-success save-binding-btn" disabled>
|
||||
<i class="fas fa-save"></i> Salva
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger delete-binding-btn">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</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://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
const $globalError = $('#globalError');
|
||||
|
||||
$('.binding-select').each(function() {
|
||||
const fieldId = $(this).data('field-id');
|
||||
const initialVal = $(this).val();
|
||||
|
||||
$(this).select2({
|
||||
width: '220px',
|
||||
ajax: {
|
||||
url: 'search_customfield_values.php',
|
||||
dataType: 'json',
|
||||
delay: 200,
|
||||
data: params => ({
|
||||
field_id: fieldId,
|
||||
q: params.term || '',
|
||||
limit: 50
|
||||
}),
|
||||
processResults: data => ({
|
||||
results: data.results || []
|
||||
})
|
||||
},
|
||||
minimumInputLength: 0
|
||||
});
|
||||
|
||||
// Abilito Salva solo quando il valore cambia davvero.
|
||||
$(this).data('original-val', initialVal);
|
||||
});
|
||||
|
||||
$('.binding-select').on('change', function() {
|
||||
const $row = $(this).closest('tr');
|
||||
const changed = String($(this).val()) !== String($(this).data('original-val'));
|
||||
$row.find('.save-binding-btn').prop('disabled', !changed);
|
||||
});
|
||||
|
||||
$('.save-binding-btn').on('click', function() {
|
||||
const $row = $(this).closest('tr');
|
||||
const $select = $row.find('.binding-select');
|
||||
const selectedData = $select.select2('data')[0] || {};
|
||||
const $status = $row.find('.row-status');
|
||||
const $btn = $(this);
|
||||
|
||||
$globalError.hide();
|
||||
$btn.prop('disabled', true);
|
||||
$status.text('Salvataggio...').removeClass('text-success text-danger').addClass('text-muted');
|
||||
|
||||
$.post('save_binding.php', {
|
||||
mapping_id: $row.data('mapping-id'),
|
||||
field_id: $row.data('field-id'),
|
||||
template_id: $row.data('template-id'),
|
||||
json_value: String($row.data('json-value')),
|
||||
lims_value_id: $select.val(),
|
||||
lims_value: selectedData.text || ''
|
||||
}).then(resp => {
|
||||
if (resp && resp.success) {
|
||||
$status.text('Salvato').removeClass('text-muted').addClass('text-success');
|
||||
$select.data('original-val', $select.val());
|
||||
} else {
|
||||
throw new Error((resp && resp.error) || 'Errore salvataggio');
|
||||
}
|
||||
}).catch(err => {
|
||||
$status.text('Errore').removeClass('text-muted').addClass('text-danger');
|
||||
$globalError.text(err.message || 'Errore durante il salvataggio.').show();
|
||||
$btn.prop('disabled', false);
|
||||
});
|
||||
});
|
||||
|
||||
$('.delete-binding-btn').on('click', function() {
|
||||
if (!confirm('Eliminare questo binding?')) return;
|
||||
const $row = $(this).closest('tr');
|
||||
const $btn = $(this);
|
||||
$globalError.hide();
|
||||
$btn.prop('disabled', true);
|
||||
|
||||
$.post('delete_binding.php', {
|
||||
id: $row.data('id')
|
||||
}).then(resp => {
|
||||
if (resp && resp.success) {
|
||||
$row.fadeOut(200, () => $row.remove());
|
||||
} else {
|
||||
throw new Error((resp && resp.error) || 'Errore eliminazione');
|
||||
}
|
||||
}).catch(err => {
|
||||
$globalError.text(err.message || 'Errore durante l\'eliminazione.').show();
|
||||
$btn.prop('disabled', false);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
// Helpers for JSON -> LIMS value bindings (table json_lims_binding).
|
||||
|
||||
function binding_is_list_field(array $mapping): bool
|
||||
{
|
||||
$hasList = (int) ($mapping['has_list'] ?? 0) === 1;
|
||||
$isMultiChoice = strcasecmp(trim((string) ($mapping['data_type'] ?? '')), 'SceltaMultipla') === 0;
|
||||
return $hasList || $isMultiChoice;
|
||||
}
|
||||
|
||||
function binding_lookup(PDO $pdo, int $mappingId, string $jsonValue): ?array
|
||||
{
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT id, lims_value_id, lims_value
|
||||
FROM json_lims_binding
|
||||
WHERE mapping_id = ? AND json_value = ?
|
||||
LIMIT 1"
|
||||
);
|
||||
$stmt->execute([$mappingId, $jsonValue]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
function binding_upsert(
|
||||
PDO $pdo,
|
||||
int $templateId,
|
||||
int $mappingId,
|
||||
int $fieldId,
|
||||
string $jsonValue,
|
||||
int $limsValueId,
|
||||
string $limsValue,
|
||||
?int $createdBy
|
||||
): void {
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO json_lims_binding
|
||||
(template_id, mapping_id, field_id, json_value, lims_value_id, lims_value, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
lims_value_id = VALUES(lims_value_id),
|
||||
lims_value = VALUES(lims_value),
|
||||
field_id = VALUES(field_id),
|
||||
template_id = VALUES(template_id)"
|
||||
);
|
||||
$stmt->execute([$templateId, $mappingId, $fieldId, $jsonValue, $limsValueId, $limsValue, $createdBy]);
|
||||
}
|
||||
|
||||
// LIMS list values for a field, reusing the cache/customfield_{id}.json cache (1h).
|
||||
function binding_get_lims_values(int $fieldId): array
|
||||
{
|
||||
static $memo = [];
|
||||
if ($fieldId <= 0) {
|
||||
return [];
|
||||
}
|
||||
if (array_key_exists($fieldId, $memo)) {
|
||||
return $memo[$fieldId];
|
||||
}
|
||||
|
||||
$cacheDir = dirname(__DIR__) . '/cache';
|
||||
$cacheFile = $cacheDir . '/customfield_' . $fieldId . '.json';
|
||||
|
||||
try {
|
||||
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 3600)) {
|
||||
$values = json_decode(file_get_contents($cacheFile), true);
|
||||
} else {
|
||||
require_once __DIR__ . '/VisualLimsApiClient.class.php';
|
||||
$api = VisualLimsApiClient::getInstance();
|
||||
$data = $api->get("CustomField($fieldId)?\$expand=CustomFieldsValues");
|
||||
$values = $data['CustomFieldsValues'] ?? [];
|
||||
if (!is_dir($cacheDir)) {
|
||||
mkdir($cacheDir, 0777, true);
|
||||
}
|
||||
file_put_contents($cacheFile, json_encode($values));
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
error_log("binding_get_lims_values failed for field $fieldId: " . $e->getMessage());
|
||||
$values = [];
|
||||
}
|
||||
|
||||
if (!is_array($values)) {
|
||||
$values = [];
|
||||
}
|
||||
|
||||
return $memo[$fieldId] = $values;
|
||||
}
|
||||
|
||||
// Exactly one case-insensitive match by Valore -> that value, otherwise null.
|
||||
function binding_auto_match(array $limsValues, string $jsonValue): ?array
|
||||
{
|
||||
$needle = mb_strtolower(trim($jsonValue));
|
||||
if ($needle === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
foreach ($limsValues as $v) {
|
||||
$valore = (string) ($v['Valore'] ?? '');
|
||||
if (mb_strtolower(trim($valore)) === $needle) {
|
||||
$matches[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return count($matches) === 1 ? $matches[0] : null;
|
||||
}
|
||||
|
||||
// Scrive il valore risolto sui record indicati (datadb_ids gia' delimita l'import corrente).
|
||||
function binding_apply_to_details(
|
||||
PDO $pdo,
|
||||
int $mappingId,
|
||||
string $limsValue,
|
||||
array $datadbIds
|
||||
): int {
|
||||
$datadbIds = array_values(array_filter(array_map('intval', $datadbIds)));
|
||||
if (empty($datadbIds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($datadbIds), '?'));
|
||||
$sql = "UPDATE import_data_details
|
||||
SET field_value = ?
|
||||
WHERE mapping_id = ?
|
||||
AND id IN ($placeholders)";
|
||||
|
||||
$params = array_merge([$limsValue, $mappingId], $datadbIds);
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
// Elimina un binding JSON -> LIMS. Ritorna JSON.
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/class/db-functions.php';
|
||||
include dirname(__DIR__) . '/../extra/auth.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
ini_set('display_errors', '0');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
if (!Auth::check()) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = intval($_POST['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
http_response_code(422);
|
||||
echo json_encode(['success' => false, 'error' => 'Missing id']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
$stmt = $pdo->prepare("DELETE FROM json_lims_binding WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
echo json_encode(['success' => true, 'deleted' => $stmt->rowCount()]);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -12,6 +12,7 @@ if (!file_exists(__DIR__ . '/import_debug.log')) {
|
||||
error_log("Inizio importazione alle " . date('Y-m-d H:i:s'));
|
||||
|
||||
include('include/headscript.php');
|
||||
require_once(__DIR__ . '/class/binding-functions.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"));
|
||||
@@ -61,7 +62,8 @@ $stmt = $pdo->prepare("
|
||||
field_label,
|
||||
field_id,
|
||||
main_field,
|
||||
auto_value
|
||||
auto_value,
|
||||
has_list
|
||||
FROM template_mapping
|
||||
WHERE template_id = ?
|
||||
");
|
||||
@@ -84,6 +86,13 @@ foreach ($allMappings as $mapping) {
|
||||
|
||||
// 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') {
|
||||
@@ -107,6 +116,14 @@ foreach ($selected_rows as $loopIndex => $rowIndex) {
|
||||
$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,
|
||||
@@ -115,7 +132,7 @@ foreach ($selected_rows as $loopIndex => $rowIndex) {
|
||||
$user_id,
|
||||
null,
|
||||
date('Y-m-d'),
|
||||
$excelrow,
|
||||
$excelrowDb,
|
||||
$default_idclient // Aggiungi idclient
|
||||
];
|
||||
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate, excelrow, idclient) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
@@ -227,6 +244,80 @@ foreach ($selected_rows as $loopIndex => $rowIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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']);
|
||||
}
|
||||
@@ -239,5 +330,28 @@ foreach ($selected_rows as $loopIndex => $rowIndex) {
|
||||
|
||||
$_SESSION['inserted_ids'] = $insertedIds;
|
||||
|
||||
header("Location: imported.php?id=" . urlencode($template_id) . "&importref=" . urlencode($importReferenceCode));
|
||||
$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;
|
||||
|
||||
@@ -173,7 +173,8 @@ error_log("Loaded JSON import template: " . print_r($template, true));
|
||||
|
||||
<div class="mb-3 text">
|
||||
<a href="imported.php?id=<?= $id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
||||
<a href="tolims.php?id=<?= $id ?>" class="btn btn-success">To LIMS (l)</a>
|
||||
<a href="tolims.php?id=<?= $id ?>" class="btn btn-success me-2">To LIMS (l)</a>
|
||||
<a href="bindings_manage.php?template_id=<?= $id ?>" class="btn btn-outline-secondary">Binding JSON -> LIMS</a>
|
||||
</div>
|
||||
|
||||
<div class="card radius-10">
|
||||
@@ -384,42 +385,51 @@ error_log("Loaded JSON import template: " . print_r($template, true));
|
||||
}
|
||||
|
||||
function addJsonRow(jsonPayload, reference, sourceType) {
|
||||
const normalizedPayload = normalizeJsonPayload(jsonPayload);
|
||||
const flattened = flattenJson(normalizedPayload);
|
||||
// Ogni elemento di data[] diventa una riga (non colonne data.0.*, data.1.*).
|
||||
const records = extractRecords(jsonPayload);
|
||||
|
||||
if (INCLUDE_SOURCE_CODE_COLUMN) {
|
||||
flattened.source_code = reference;
|
||||
flattened.source_type = sourceType;
|
||||
}
|
||||
records.forEach((record, recordIndex) => {
|
||||
const flattened = flattenJson(record);
|
||||
|
||||
const newColumns = Object.keys(flattened).filter(col => !columns.includes(col));
|
||||
columns = columns.concat(newColumns);
|
||||
const rowReference = records.length > 1 ?
|
||||
reference + '#' + (recordIndex + 1) :
|
||||
reference;
|
||||
|
||||
jsonRows.push({
|
||||
excelrow: 'JSON-' + (jsonRows.length + 1),
|
||||
reference: reference,
|
||||
sourceType: sourceType,
|
||||
flat: flattened
|
||||
if (INCLUDE_SOURCE_CODE_COLUMN) {
|
||||
flattened.source_code = rowReference;
|
||||
flattened.source_type = sourceType;
|
||||
}
|
||||
|
||||
const newColumns = Object.keys(flattened).filter(col => !columns.includes(col));
|
||||
columns = columns.concat(newColumns);
|
||||
|
||||
jsonRows.push({
|
||||
excelrow: 'JSON-' + (jsonRows.length + 1),
|
||||
reference: rowReference,
|
||||
sourceType: sourceType,
|
||||
flat: flattened
|
||||
});
|
||||
});
|
||||
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function normalizeJsonPayload(payload) {
|
||||
// Record da trasformare in righe: gli oggetti in data[], altrimenti il payload stesso.
|
||||
function extractRecords(payload) {
|
||||
if (
|
||||
UNWRAP_SINGLE_DATA_ITEM &&
|
||||
payload &&
|
||||
typeof payload === 'object' &&
|
||||
!Array.isArray(payload) &&
|
||||
Array.isArray(payload.data) &&
|
||||
payload.data.length === 1 &&
|
||||
payload.data[0] &&
|
||||
typeof payload.data[0] === 'object'
|
||||
payload.data.length > 0
|
||||
) {
|
||||
return payload.data[0];
|
||||
const items = payload.data.filter(item => item && typeof item === 'object');
|
||||
if (items.length > 0) {
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
return payload;
|
||||
return [payload];
|
||||
}
|
||||
|
||||
function flattenJson(value, prefix = '', result = {}) {
|
||||
|
||||
@@ -1301,9 +1301,17 @@ $gridMeta = [
|
||||
<?php include('include/topbar.php'); ?>
|
||||
<div class="page-wrapper">
|
||||
<div class="page-content">
|
||||
<?php $autoBoundCount = isset($_GET['autobound']) ? (int) $_GET['autobound'] : 0; ?>
|
||||
<?php if ($autoBoundCount > 0): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<?= $autoBoundCount ?> valore/i collegato/i automaticamente al LIMS durante l'import.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="mb-3 text d-flex align-items-center gap-2">
|
||||
<a href="imported.php?id=<?= $template_id ?>" class="btn btn-warning me-2">Imported (i)</a>
|
||||
<a href="tolims.php?id=<?= $template_id ?>" class="btn btn-success">To LIMS (l)</a>
|
||||
<a href="bindings_manage.php?template_id=<?= $template_id ?>" class="btn btn-outline-secondary">Binding JSON -> LIMS</a>
|
||||
<?php if ($importref === ''): ?>
|
||||
<span class="ms-3">
|
||||
<label class="form-check-label" style="font-size: 13px; cursor: pointer;">
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
<ul>
|
||||
<li> <a href="quotations.php"><i class='bx bx-radio-circle'></i><?php echo $quotationstitle; ?></a>
|
||||
</li>
|
||||
<li> <a href="bindings_manage.php"><i class='bx bx-radio-circle'></i>Binding JSON -> LIMS</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
<?php
|
||||
include('include/headscript.php');
|
||||
|
||||
// Binding preparati da import_insert.php (da risolvere + collegati in automatico).
|
||||
$pending = $_SESSION['pending_bindings'] ?? null;
|
||||
|
||||
if (empty($pending) || (empty($pending['items']) && empty($pending['auto']) && empty($pending['saved']))) {
|
||||
// Niente da mostrare: vado alla griglia.
|
||||
$tid = $pending['template_id'] ?? ($_SESSION['template_id'] ?? null);
|
||||
$ref = $pending['importref'] ?? '';
|
||||
unset($_SESSION['pending_bindings']);
|
||||
|
||||
if ($tid) {
|
||||
header("Location: imported.php?id=" . urlencode($tid) . "&importref=" . urlencode($ref));
|
||||
} else {
|
||||
header("Location: xlstemplates_grid.php");
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
$templateId = (int) $pending['template_id'];
|
||||
$importRef = (string) $pending['importref'];
|
||||
$items = $pending['items'] ?? [];
|
||||
$autoItems = $pending['auto'] ?? [];
|
||||
$savedItems = $pending['saved'] ?? [];
|
||||
|
||||
// Righe gia' risolte (modificabili): auto-collegate + binding gia' salvati.
|
||||
$resolvedItems = [];
|
||||
foreach ($autoItems as $a) {
|
||||
$a['badge'] = 'auto';
|
||||
$a['badge_class'] = 'bg-success';
|
||||
$resolvedItems[] = $a;
|
||||
}
|
||||
foreach ($savedItems as $s) {
|
||||
$s['badge'] = 'salvato';
|
||||
$s['badge_class'] = 'bg-secondary';
|
||||
$resolvedItems[] = $s;
|
||||
}
|
||||
|
||||
$db = DBHandlerSelect::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
$stmt = $pdo->prepare("SELECT name FROM excel_templates WHERE id = ?");
|
||||
$stmt->execute([$templateId]);
|
||||
$templateName = $stmt->fetchColumn() ?: ('Template ' . $templateId);
|
||||
?>
|
||||
<!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 href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.json-value {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.binding-status {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
td .select2-container {
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
/* Allinea l'altezza di select2 a form-select/btn di Bootstrap */
|
||||
.select2-container--default .select2-selection--single {
|
||||
height: 38px;
|
||||
border-color: #ced4da;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 36px;
|
||||
}
|
||||
</style>
|
||||
<title>Binding JSON -> LIMS - <?= 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="card radius-10">
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2">
|
||||
<div>
|
||||
<h6 class="mb-0">Binding JSON -> LIMS</h6>
|
||||
<small><?= htmlspecialchars($templateName) ?> - Template ID: <?= $templateId ?></small>
|
||||
</div>
|
||||
<a href="bindings_manage.php?template_id=<?= $templateId ?>" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-cog"></i> Gestione binding
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<?php if (!empty($items)): ?>
|
||||
<div class="alert alert-info">
|
||||
Alcuni valori importati dal JSON non hanno ancora una corrispondenza con i valori del LIMS.
|
||||
Seleziona il valore LIMS corretto per ciascuno e conferma. I binding verranno salvati e
|
||||
riutilizzati nelle importazioni successive.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($autoItems)): ?>
|
||||
<div class="alert alert-success">
|
||||
<?= count($autoItems) ?> valore/i collegato/i automaticamente (corrispondenza esatta con il LIMS).
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="bindingError" class="alert alert-danger" style="display:none;"></div>
|
||||
|
||||
<form id="bindingForm">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Campo (template_mapping)</th>
|
||||
<th>Valore JSON</th>
|
||||
<th>Valore LIMS</th>
|
||||
<th style="width:210px;">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($items as $idx => $item): ?>
|
||||
<tr class="binding-row"
|
||||
data-index="<?= $idx ?>"
|
||||
data-mapping-id="<?= (int) $item['mapping_id'] ?>"
|
||||
data-field-id="<?= (int) $item['field_id'] ?>"
|
||||
data-json-value="<?= htmlspecialchars($item['json_value'], ENT_QUOTES) ?>"
|
||||
data-datadb-ids="<?= htmlspecialchars(json_encode($item['datadb_ids']), ENT_QUOTES) ?>">
|
||||
<td class="text-muted"><?= htmlspecialchars($item['field_label']) ?></td>
|
||||
<td class="json-value"><?= htmlspecialchars($item['json_value']) ?></td>
|
||||
<td>
|
||||
<select class="form-select binding-select" data-field-id="<?= (int) $item['field_id'] ?>">
|
||||
<option value="">Seleziona valore LIMS...</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary skip-binding-btn">Nessuna corrispondenza</button>
|
||||
<div class="binding-status text-muted mt-1">In attesa</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php foreach ($resolvedItems as $res): ?>
|
||||
<tr class="binding-row"
|
||||
data-mapping-id="<?= (int) $res['mapping_id'] ?>"
|
||||
data-field-id="<?= (int) $res['field_id'] ?>"
|
||||
data-json-value="<?= htmlspecialchars($res['json_value'], ENT_QUOTES) ?>"
|
||||
data-datadb-ids="<?= htmlspecialchars(json_encode($res['datadb_ids']), ENT_QUOTES) ?>">
|
||||
<td class="text-muted"><?= htmlspecialchars($res['field_label']) ?></td>
|
||||
<td class="json-value"><?= htmlspecialchars($res['json_value']) ?></td>
|
||||
<td>
|
||||
<select class="form-select binding-select" data-field-id="<?= (int) $res['field_id'] ?>">
|
||||
<option value="<?= (int) $res['lims_value_id'] ?>" selected><?= htmlspecialchars($res['lims_value']) ?></option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary skip-binding-btn">Nessuna corrispondenza</button>
|
||||
<div class="binding-status mt-1"><span class="badge <?= $res['badge_class'] ?>"><?= $res['badge'] ?></span></div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end gap-2 mt-3">
|
||||
<a href="imported.php?id=<?= $templateId ?>&importref=<?= urlencode($importRef) ?>"
|
||||
class="btn btn-outline-secondary">Salta per ora</a>
|
||||
<button type="submit" class="btn btn-primary" id="confirmBindingsBtn" disabled>
|
||||
Conferma e prosegui
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</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://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
const TEMPLATE_ID = <?= $templateId ?>;
|
||||
const IMPORT_REF = <?= json_encode($importRef) ?>;
|
||||
const CONTINUE_URL = 'imported.php?id=' + TEMPLATE_ID + '&importref=' + encodeURIComponent(IMPORT_REF);
|
||||
|
||||
const $form = $('#bindingForm');
|
||||
const $btn = $('#confirmBindingsBtn');
|
||||
const $error = $('#bindingError');
|
||||
|
||||
// Dropdown valori LIMS per riga (search_customfield_values.php).
|
||||
$('.binding-select').each(function() {
|
||||
const fieldId = $(this).data('field-id');
|
||||
$(this).select2({
|
||||
placeholder: 'Seleziona valore LIMS...',
|
||||
width: '100%',
|
||||
ajax: {
|
||||
url: 'search_customfield_values.php',
|
||||
dataType: 'json',
|
||||
delay: 200,
|
||||
data: params => ({
|
||||
field_id: fieldId,
|
||||
q: params.term || '',
|
||||
limit: 50
|
||||
}),
|
||||
processResults: data => ({
|
||||
results: data.results || []
|
||||
})
|
||||
},
|
||||
minimumInputLength: 0
|
||||
});
|
||||
});
|
||||
|
||||
// Una riga e' pronta se ha un valore scelto oppure e' marcata "nessuna corrispondenza".
|
||||
function refreshButton() {
|
||||
const allReady = $('.binding-row').toArray().every(row => {
|
||||
const $row = $(row);
|
||||
return $row.hasClass('is-skipped') || $row.find('.binding-select').val();
|
||||
});
|
||||
$btn.prop('disabled', !allReady);
|
||||
}
|
||||
|
||||
$('.binding-select').on('change', refreshButton);
|
||||
refreshButton();
|
||||
|
||||
// "Nessuna corrispondenza": azzera il valore importato, nessun binding salvato.
|
||||
$('.skip-binding-btn').on('click', function() {
|
||||
const $row = $(this).closest('.binding-row');
|
||||
const $select = $row.find('.binding-select');
|
||||
const $status = $row.find('.binding-status');
|
||||
const skipped = $row.toggleClass('is-skipped').hasClass('is-skipped');
|
||||
|
||||
$(this).toggleClass('btn-outline-secondary', !skipped).toggleClass('btn-secondary', skipped);
|
||||
$select.val(null).trigger('change').prop('disabled', skipped);
|
||||
$status.text(skipped ? 'Nessuna corrispondenza' : 'In attesa');
|
||||
refreshButton();
|
||||
});
|
||||
|
||||
$form.on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
$error.hide();
|
||||
$btn.prop('disabled', true).text('Salvataggio...');
|
||||
|
||||
const tasks = $('.binding-row').toArray().map(row => {
|
||||
const $row = $(row);
|
||||
const $status = $row.find('.binding-status');
|
||||
const datadbIds = JSON.stringify($row.data('datadb-ids') || []);
|
||||
const jsonValue = String($row.data('json-value'));
|
||||
|
||||
// Riga senza corrispondenza: azzera il valore, niente binding.
|
||||
if ($row.hasClass('is-skipped')) {
|
||||
return $.post('skip_binding.php', {
|
||||
mapping_id: $row.data('mapping-id'),
|
||||
json_value: jsonValue,
|
||||
datadb_ids: datadbIds
|
||||
}).then(resp => {
|
||||
if (resp && resp.success) {
|
||||
$status.text('Azzerato').removeClass('text-muted').addClass('text-success');
|
||||
return true;
|
||||
}
|
||||
$status.text('Errore').addClass('text-danger');
|
||||
throw new Error((resp && resp.error) || 'Errore azzeramento valore');
|
||||
});
|
||||
}
|
||||
|
||||
const $select = $row.find('.binding-select');
|
||||
const selectedData = $select.select2('data')[0] || {};
|
||||
|
||||
return $.post('save_binding.php', {
|
||||
mapping_id: $row.data('mapping-id'),
|
||||
field_id: $row.data('field-id'),
|
||||
template_id: TEMPLATE_ID,
|
||||
json_value: jsonValue,
|
||||
lims_value_id: $select.val(),
|
||||
lims_value: selectedData.text || '',
|
||||
datadb_ids: datadbIds
|
||||
}).then(resp => {
|
||||
if (resp && resp.success) {
|
||||
$status.text('Salvato').removeClass('text-muted').addClass('text-success');
|
||||
return true;
|
||||
}
|
||||
$status.text('Errore').addClass('text-danger');
|
||||
throw new Error((resp && resp.error) || 'Errore salvataggio binding');
|
||||
});
|
||||
});
|
||||
|
||||
Promise.all(tasks)
|
||||
.then(() => {
|
||||
window.location.href = CONTINUE_URL;
|
||||
})
|
||||
.catch(err => {
|
||||
$error.text(err.message || 'Errore durante il salvataggio dei binding.').show();
|
||||
$btn.prop('disabled', false).text('Conferma e prosegui');
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
// Salva un binding JSON -> LIMS e lo applica ai record appena importati. Ritorna JSON.
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/class/db-functions.php';
|
||||
require_once __DIR__ . '/class/binding-functions.php';
|
||||
include dirname(__DIR__) . '/../extra/auth.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
ini_set('display_errors', '0');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
if (!Auth::check()) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$mappingId = intval($_POST['mapping_id'] ?? 0);
|
||||
$fieldId = intval($_POST['field_id'] ?? 0);
|
||||
$templateId = intval($_POST['template_id'] ?? 0);
|
||||
$jsonValue = (string) ($_POST['json_value'] ?? '');
|
||||
$limsValueId = intval($_POST['lims_value_id'] ?? 0);
|
||||
$limsValue = (string) ($_POST['lims_value'] ?? '');
|
||||
|
||||
$datadbIds = [];
|
||||
if (isset($_POST['datadb_ids'])) {
|
||||
$decoded = json_decode($_POST['datadb_ids'], true);
|
||||
if (is_array($decoded)) {
|
||||
$datadbIds = $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mappingId <= 0 || $templateId <= 0 || $jsonValue === '' || $limsValueId <= 0) {
|
||||
http_response_code(422);
|
||||
echo json_encode(['success' => false, 'error' => 'Missing required parameters']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
$createdBy = null;
|
||||
if (Auth::user()) {
|
||||
$createdBy = (int) Auth::user()->present()->id;
|
||||
}
|
||||
|
||||
if ($fieldId <= 0) {
|
||||
$stmt = $pdo->prepare("SELECT field_id FROM template_mapping WHERE id = ?");
|
||||
$stmt->execute([$mappingId]);
|
||||
$fieldId = (int) ($stmt->fetchColumn() ?: 0);
|
||||
}
|
||||
|
||||
binding_upsert($pdo, $templateId, $mappingId, $fieldId, $jsonValue, $limsValueId, $limsValue, $createdBy);
|
||||
|
||||
$applied = 0;
|
||||
if (!empty($datadbIds)) {
|
||||
$applied = binding_apply_to_details($pdo, $mappingId, $limsValue, $datadbIds);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'applied_rows' => $applied,
|
||||
'mapping_id' => $mappingId,
|
||||
'json_value' => $jsonValue,
|
||||
'lims_value' => $limsValue,
|
||||
'lims_value_id' => $limsValueId,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
// "Nessuna corrispondenza": azzera il valore grezzo nei record importati, senza salvare binding.
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/class/db-functions.php';
|
||||
require_once __DIR__ . '/class/binding-functions.php';
|
||||
include dirname(__DIR__) . '/../extra/auth.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
ini_set('display_errors', '0');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
if (!Auth::check()) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$mappingId = intval($_POST['mapping_id'] ?? 0);
|
||||
$jsonValue = (string) ($_POST['json_value'] ?? '');
|
||||
|
||||
$datadbIds = [];
|
||||
if (isset($_POST['datadb_ids'])) {
|
||||
$decoded = json_decode($_POST['datadb_ids'], true);
|
||||
if (is_array($decoded)) {
|
||||
$datadbIds = $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mappingId <= 0 || $jsonValue === '') {
|
||||
http_response_code(422);
|
||||
echo json_encode(['success' => false, 'error' => 'Missing required parameters']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
$cleared = binding_apply_to_details($pdo, $mappingId, '', $datadbIds);
|
||||
|
||||
// Rimuovo un eventuale binding gia' salvato (es. auto-collegato) per coerenza.
|
||||
$del = $pdo->prepare("DELETE FROM json_lims_binding WHERE mapping_id = ? AND json_value = ?");
|
||||
$del->execute([$mappingId, $jsonValue]);
|
||||
|
||||
echo json_encode(['success' => true, 'cleared_rows' => $cleared]);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
Reference in New Issue
Block a user