280 lines
10 KiB
PHP
280 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* Validate rows before export to LIMS.
|
|
*
|
|
* Expects POST JSON: { rows: [ { iddatadb: int, index: int }, ... ] }
|
|
* Returns JSON:
|
|
* {
|
|
* success: true,
|
|
* results: {
|
|
* "<index>": {
|
|
* valid: bool,
|
|
* iddatadb: int,
|
|
* errors: [ { field: "<data-col>", message: "..." }, ... ]
|
|
* }
|
|
* }
|
|
* }
|
|
*
|
|
* Validators are closures registered in $validators[].
|
|
* Each receives ($iddatadb, $ctx) and returns an array of errors (or empty []).
|
|
* $ctx holds all prefetched data (record, parts, field values, mappings, etc.).
|
|
* To add a new rule — just append another closure to $validators.
|
|
*/
|
|
include('include/headscript.php');
|
|
|
|
$dbHandler = DBHandlerSelect::getInstance();
|
|
$pdo = $dbHandler->getConnection();
|
|
|
|
header("Content-Type: application/json");
|
|
|
|
// ── Validators ──────────────────────────────────────────────────────────────
|
|
// Each validator is a closure: fn(int $iddatadb, array $ctx): array<{field,message}>
|
|
// $ctx keys: record, parts, fieldValues, requiredFixed, requiredMappings, fixedAliasMap
|
|
|
|
$validators = [];
|
|
|
|
// 1. Every part must have a valid Matrice
|
|
// Without Matrice the LIMS API rejects the Campione creation.
|
|
$validators[] = function (int $iddatadb, array $ctx): array {
|
|
$parts = $ctx['parts'];
|
|
if (empty($parts)) {
|
|
return [];
|
|
}
|
|
$missing = [];
|
|
foreach ($parts as $p) {
|
|
$matrice = (int)($p['idmatrice'] ?? 0);
|
|
if ($matrice <= 0) {
|
|
$label = $p['part_number'] ?: ($p['part_description'] ?: '(senza nome)');
|
|
$missing[] = $label;
|
|
}
|
|
}
|
|
if (!empty($missing)) {
|
|
return [[
|
|
'field' => 'parts',
|
|
'message' => 'Matrice mancante — il LIMS rifiuterà l\'esportazione. '
|
|
. 'Part senza matrice: ' . implode(', ', $missing)
|
|
. '. Aprire la sezione Parts e assegnare la matrice.',
|
|
]];
|
|
}
|
|
return [];
|
|
};
|
|
|
|
// 2. ConsegnaRichiesta must be filled and >= today
|
|
$validators[] = function (int $iddatadb, array $ctx): array {
|
|
$record = $ctx['record'] ?? null;
|
|
if (!$record) {
|
|
return [];
|
|
}
|
|
|
|
$consegna = $record['consegna_richiesta'] ?? null;
|
|
|
|
if (empty($consegna)) {
|
|
return [[
|
|
'field' => 'ConsegnaRichiesta',
|
|
'message' => 'ConsegnaRichiesta è obbligatorio.',
|
|
]];
|
|
}
|
|
|
|
$consegnaDate = DateTime::createFromFormat('Y-m-d', $consegna) ?: DateTime::createFromFormat('Y-m-d H:i:s', $consegna);
|
|
$today = new DateTime('today');
|
|
|
|
if ($consegnaDate && $consegnaDate < $today) {
|
|
return [[
|
|
'field' => 'ConsegnaRichiesta',
|
|
'message' => 'ConsegnaRichiesta deve essere uguale o superiore alla data odierna (' . $today->format('Y-m-d') . ').',
|
|
]];
|
|
}
|
|
|
|
return [];
|
|
};
|
|
|
|
// 3. All LIMS-mandatory fields must be filled.
|
|
$validators[] = function (int $iddatadb, array $ctx): array {
|
|
$record = $ctx['record'] ?? null;
|
|
if (!$record) {
|
|
return [];
|
|
}
|
|
|
|
$errors = [];
|
|
|
|
// Fixed fields (stored as columns in datadb)
|
|
foreach (($ctx['requiredFixed'] ?? []) as $key => $label) {
|
|
$col = $ctx['fixedAliasMap'][$key] ?? null;
|
|
$val = $col !== null ? ($record[$col] ?? null) : null;
|
|
if ($val === null || $val === '' || (int) $val === 0) {
|
|
$errors[] = [
|
|
'field' => $key,
|
|
'message' => $label . ' è obbligatorio.',
|
|
];
|
|
}
|
|
}
|
|
|
|
// Custom fields (values stored in import_data_details, keyed by mapping_id)
|
|
foreach (($ctx['requiredCustom'] ?? []) as $cf) {
|
|
$val = $ctx['customValues'][(int) $cf['mapping_id']] ?? null;
|
|
if ($val === null || trim((string) $val) === '') {
|
|
$errors[] = [
|
|
'field' => 'field_label:' . $cf['field_label'],
|
|
'message' => rtrim($cf['field_label'], ': ') . ' è obbligatorio.',
|
|
];
|
|
}
|
|
}
|
|
|
|
return $errors;
|
|
};
|
|
|
|
// Logical fixed_field_key - real datadb column (mirrors imported.php $fixedAliasMap)
|
|
$fixedAliasMap = [
|
|
'ClienteResponsabile' => 'cliente_responsabile_id',
|
|
'ClienteFornitore' => 'cliente_fornitore_id',
|
|
'ClienteAnalisi' => 'clienteAnalisi',
|
|
'MoltiplicatorePrezzo' => 'moltiplicatore_prezzo_id',
|
|
'AnagraficaCertestObject' => 'anagrafica_certest_object_id',
|
|
'AnagraficaCertestService' => 'anagrafica_certest_service_id',
|
|
'ConsegnaRichiesta' => 'consegna_richiesta',
|
|
];
|
|
|
|
// Fixed keys NOT enforced by the generic mandatory check above:
|
|
// - ConsegnaRichiesta: handled by its dedicated validator (also checks the date)
|
|
// - ClienteFornitore / ClienteAnalisi: nullable placeholders, sent as null on
|
|
// export and accepted by LIMS.
|
|
$skipRequiredFixed = ['ConsegnaRichiesta', 'ClienteFornitore', 'ClienteAnalisi'];
|
|
|
|
// ── Main ────────────────────────────────────────────────────────────────────
|
|
|
|
try {
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
$rows = $input['rows'] ?? [];
|
|
|
|
if (empty($rows)) {
|
|
echo json_encode(['success' => false, 'message' => 'No rows provided']);
|
|
exit;
|
|
}
|
|
|
|
// ── Prefetch all data in bulk ───────────────────────────────────────────
|
|
|
|
$iddatadbList = array_column($rows, 'iddatadb');
|
|
$placeholders = implode(',', array_fill(0, count($iddatadbList), '?'));
|
|
|
|
// Records (datadb) — templateid + fixed-field columns for mandatory validation
|
|
$stmt = $pdo->prepare("
|
|
SELECT iddatadb, templateid, consegna_richiesta,
|
|
cliente_responsabile_id, moltiplicatore_prezzo_id,
|
|
anagrafica_certest_object_id, anagrafica_certest_service_id,
|
|
cliente_fornitore_id, clienteAnalisi
|
|
FROM datadb
|
|
WHERE iddatadb IN ($placeholders)
|
|
");
|
|
$stmt->execute($iddatadbList);
|
|
$recordsInfo = [];
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$recordsInfo[(int)$r['iddatadb']] = $r;
|
|
}
|
|
|
|
// Parts (full rows, so validators can report which parts have issues)
|
|
$stmt = $pdo->prepare("
|
|
SELECT iddatadb, part_number, part_description, idmatrice
|
|
FROM identification_parts
|
|
WHERE iddatadb IN ($placeholders)
|
|
");
|
|
$stmt->execute($iddatadbList);
|
|
$partsInfo = [];
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$partsInfo[(int)$r['iddatadb']][] = $r;
|
|
}
|
|
|
|
// Mandatory-field config per template
|
|
$templateIds = array_values(array_unique(array_filter(array_map(
|
|
fn ($r) => (int)($r['templateid'] ?? 0),
|
|
$recordsInfo
|
|
))));
|
|
|
|
$requiredFixedByTemplate = []; // template_id => [ fixed_field_key => label ]
|
|
$requiredCustomByTemplate = []; // template_id => [ { mapping_id, field_label }, ... ]
|
|
|
|
if (!empty($templateIds)) {
|
|
$tplPlaceholders = implode(',', array_fill(0, count($templateIds), '?'));
|
|
|
|
// Required fixed fields (is_required synced from LIMS ObbligatorioWeb)
|
|
$stmt = $pdo->prepare("
|
|
SELECT template_id, fixed_field_key
|
|
FROM template_fixed_mapping
|
|
WHERE template_id IN ($tplPlaceholders) AND is_required = 1
|
|
");
|
|
$stmt->execute($templateIds);
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$key = $r['fixed_field_key'];
|
|
if (in_array($key, $skipRequiredFixed, true)) {
|
|
continue;
|
|
}
|
|
$requiredFixedByTemplate[(int)$r['template_id']][$key] = $key;
|
|
}
|
|
|
|
// Required custom fields that are visible in the import grid
|
|
$stmt = $pdo->prepare("
|
|
SELECT id AS mapping_id, template_id, field_label
|
|
FROM template_mapping
|
|
WHERE template_id IN ($tplPlaceholders)
|
|
AND is_required = 1
|
|
AND is_visible_import = 1
|
|
");
|
|
$stmt->execute($templateIds);
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$requiredCustomByTemplate[(int)$r['template_id']][] = [
|
|
'mapping_id' => (int)$r['mapping_id'],
|
|
'field_label' => $r['field_label'],
|
|
];
|
|
}
|
|
}
|
|
|
|
// Custom field values per record (import_data_details.id is the FK to datadb)
|
|
$stmt = $pdo->prepare("
|
|
SELECT id AS iddatadb, mapping_id, field_value
|
|
FROM import_data_details
|
|
WHERE id IN ($placeholders)
|
|
");
|
|
$stmt->execute($iddatadbList);
|
|
$customValuesByRecord = []; // iddatadb => [ mapping_id => field_value ]
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
|
$customValuesByRecord[(int)$r['iddatadb']][(int)$r['mapping_id']] = $r['field_value'];
|
|
}
|
|
|
|
// ── Run validators per row ──────────────────────────────────────────────
|
|
|
|
$results = [];
|
|
|
|
foreach ($rows as $rowInfo) {
|
|
$iddatadb = (int)$rowInfo['iddatadb'];
|
|
$index = $rowInfo['index'];
|
|
|
|
// Build context for validators
|
|
$record = $recordsInfo[$iddatadb] ?? null;
|
|
$templateId = (int)($record['templateid'] ?? 0);
|
|
$ctx = [
|
|
'record' => $record,
|
|
'parts' => $partsInfo[$iddatadb] ?? [],
|
|
'fixedAliasMap' => $fixedAliasMap,
|
|
'requiredFixed' => $requiredFixedByTemplate[$templateId] ?? [],
|
|
'requiredCustom' => $requiredCustomByTemplate[$templateId] ?? [],
|
|
'customValues' => $customValuesByRecord[$iddatadb] ?? [],
|
|
];
|
|
|
|
$errors = [];
|
|
foreach ($validators as $validator) {
|
|
$errors = array_merge($errors, $validator($iddatadb, $ctx));
|
|
}
|
|
|
|
$results[$index] = [
|
|
'valid' => empty($errors),
|
|
'iddatadb' => $iddatadb,
|
|
'errors' => $errors,
|
|
];
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'results' => $results]);
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Validation error: " . $e->getMessage());
|
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
|
}
|