trf_certest/public/userarea/export_to_lims.php

571 lines
25 KiB
PHP

<?php
require_once "class/VisualLimsApiClient.class.php";
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
header("Content-Type: application/json");
// 🔹 Configura directory log (creala se non esiste)
$logDir = __DIR__ . '/logs/api/';
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
$uploadDir = realpath(__DIR__ . '/../photostrf') . '/';
// 🔹 Base URL API
$apiBaseUrl = 'https://93.43.5.102/limsapi/api/odata/';
// 🔹 Batch UUID — if present, all logs go to a single file
$batchUuid = $_POST['batch_uuid'] ?? null;
$writeLog = (function () use ($batchUuid, $logDir) {
$batchLogFile = $batchUuid ? $logDir . "batch_export_{$batchUuid}.log" : null;
return function ($individualPath, $content, $stepLabel = null) use ($batchLogFile) {
if ($batchLogFile) {
$header = "\n" . str_repeat("=", 60) . "\n";
if ($stepLabel) {
$header .= "[{$stepLabel}] " . date('Y-m-d H:i:s') . "\n";
}
$header .= str_repeat("=", 60) . "\n";
file_put_contents($batchLogFile, $header . $content . "\n", FILE_APPEND);
} else {
file_put_contents($individualPath, $content);
}
};
})();
// 🔹 Funzione per validare e convertire date
function validateDate($value)
{
// Prova a validare come data (accetta formati comuni)
$date = DateTime::createFromFormat('Y-m-d', $value) ?: DateTime::createFromFormat('Y-m-d H:i:s', $value);
if ($date) {
return $date->format('Y-m-d\TH:i:sP'); // Formato ISO 8601
}
return null; // Imposta null se non è una data valida
}
// 🔹 Funzione per validare e convertire date
function formatDateToExport($value)
{
$date = DateTime::createFromFormat('Y-m-d', $value) ?: DateTime::createFromFormat('Y-m-d H:i:s', $value);
if ($date) {
return $date->format('d/m/Y');
}
return null; // Imposta null se non è una data valida
}
try {
$iddatadb = $_POST['iddatadb'] ?? null;
if (!$iddatadb) {
throw new Exception("Missing iddatadb");
}
// TEMP: simulate error on every other row for testing
if (env('SIMULATE_EXPORT_LIMS') && $iddatadb % 2 === 0) {
throw new Exception("Simulated error for iddatadb $iddatadb");
}
// 🔹 STEP 1+2: Fetch Cliente ID from datadb and Schema ID from excel_templates
// Also fetch fixed fields stored in datadb
$stmt = $pdo->prepare("
SELECT d.idclient AS clienteId, et.idschema AS schemaId,
d.cliente_responsabile_id,
d.moltiplicatore_prezzo_id,
d.anagrafica_certest_object_id,
d.anagrafica_certest_service_id,
d.cliente_fornitore_id,
d.consegna_richiesta
FROM datadb as d
INNER JOIN excel_templates as et ON d.templateid = et.id
WHERE d.iddatadb = :iddatadb
LIMIT 1
");
$stmt->execute(['iddatadb' => $iddatadb]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$result) {
throw new Exception("No Cliente/Schema found for iddatadb {$iddatadb}");
}
$clienteId = (int) $result['clienteId'];
$schemaId = (int) $result['schemaId'];
// Extract fixed fields (nullable INTs)
$clienteResponsabile = !empty($result['cliente_responsabile_id']) ? (int) $result['cliente_responsabile_id'] : null;
$moltiplicatorePrezzo = !empty($result['moltiplicatore_prezzo_id']) ? (int) $result['moltiplicatore_prezzo_id'] : null;
$anagraficaObject = !empty($result['anagrafica_certest_object_id']) ? (int) $result['anagrafica_certest_object_id'] : null;
$anagraficaService = !empty($result['anagrafica_certest_service_id']) ? (int) $result['anagrafica_certest_service_id'] : null;
$clienteFornitore = !empty($result['cliente_fornitore_id']) ? (int) $result['cliente_fornitore_id'] : null;
$clienteAnalisi = !empty($result['clienteAnalisi']) ? (int) $result['clienteAnalisi'] : null;
$consegnaRichiesta = !empty($result['consegna_richiesta']) ? $result['consegna_richiesta'] : null;
// 🔹 STEP 3: Fetch Parts (including idmatrice and part id for custom fields)
$stmt = $pdo->prepare("
SELECT id AS part_id, part_number, part_description, material, color, mix, idmatrice, dateexpiry
FROM identification_parts
WHERE iddatadb = :iddatadb
");
$stmt->execute(['iddatadb' => $iddatadb]);
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 🔹 STEP 3.1: Fetch custom field values per part from identification_parts_customfields
$partIds = array_column($parts, 'part_id');
$partsCustomFields = []; // part_id => [ { field_id, value_id, value_text }, ... ]
if (!empty($partIds)) {
$placeholders = implode(',', array_fill(0, count($partIds), '?'));
$cfStmt = $pdo->prepare("
SELECT part_id, field_id, value_id, value_text
FROM identification_parts_customfields
WHERE part_id IN ({$placeholders})
");
$cfStmt->execute($partIds);
foreach ($cfStmt->fetchAll(PDO::FETCH_ASSOC) as $cfRow) {
$partsCustomFields[(int)$cfRow['part_id']][] = $cfRow;
}
}
// 🔹 STEP 4a: Auto-populate export_date / export_time fields
$stmt = $pdo->prepare("
UPDATE import_data_details idd
JOIN template_mapping m ON idd.mapping_id = m.id
SET idd.field_value = CASE m.auto_value
WHEN 'export_date' THEN :export_date
WHEN 'export_time' THEN :export_time
END
WHERE idd.id = :iddatadb
AND m.auto_value IN ('export_date', 'export_time')
");
$stmt->execute([
'iddatadb' => $iddatadb,
'export_date' => date('Y-m-d'),
'export_time' => date('H:i'),
]);
// 🔹 STEP 4: Fetch Field Values with Labels
$stmt = $pdo->prepare("
SELECT
idd.field_value,
m.field_label,
m.schema_id,
m.field_id
FROM
import_data_details as idd
JOIN template_mapping m ON idd.mapping_id = m.id
WHERE idd.id = :iddatadb
");
$stmt->execute(['iddatadb' => $iddatadb]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$fieldValues = [];
$valueMap = [];
foreach ($rows as $row) {
$fieldValues[] = [
"IdCommesseCustomFields" => (int) $row['field_id'],
"Valore" => $row['field_value'],
"FieldLabel" => $row['field_label']
];
$valueMap[(int) $row['field_id']] = $row['field_value'];
}
// Logga i fieldValues in error_log
$logFieldValues = "FieldValues dal DB (iddatadb={$iddatadb}):\n" . json_encode($fieldValues, JSON_PRETTY_PRINT);
error_log($logFieldValues);
// 🔹 Initialize API client
$api = VisualLimsApiClient::getInstance();
// 🔹 STEP 5: Create CommessaWeb
// Fixed fields are sent as direct properties — they are navigation properties on Commessa
// accepted by the XAF API even though not explicitly listed in OData $metadata
$commessaWebPayload = [
"Cliente" => $clienteId,
"SchemaCustomField" => $schemaId,
"Richiedente" => "From TRFSmart Application", // TODO: replace with real value
"Descrizione" => "From TRFSmart Application", // TODO: replace with real value
"ClienteResponsabile" => $clienteResponsabile,
"MoltiplicatorePrezzo" => $moltiplicatorePrezzo,
"AnagraficaCertestObject" => $anagraficaObject,
"AnagraficaCertestService" => $anagraficaService,
"ClienteFornitore" => $clienteFornitore, // PLACEHOLDER — to be implemented
"ClienteAnalisi" => $clienteAnalisi, // PLACEHOLDER — to be implemented
// DeliveryRequest goes to Campione, not CommessaWeb
];
// Costruisci log curl-like per STEP 5
$jsonPayload = json_encode($commessaWebPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep5 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'";
$commessaWeb = $api->post("CommessaWeb", $commessaWebPayload);
$logContentStep5 .= "\n\nRESPONSE:\n" . json_encode($commessaWeb, JSON_PRETTY_PRINT);
// Salva log
$logFileStep5 = $logDir . "commessa_create_step5_" . $iddatadb . "_" . time() . ".txt";
$writeLog($logFileStep5, $logContentStep5, "STEP 5 - Create CommessaWeb (iddatadb={$iddatadb})");
$commessaId = $commessaWeb["IdCommessa"];
$commessaWebCode = substr($commessaWeb["CodiceCommessa"] ?? "TEST CommessaWeb", 0, 30); // Limite a 30 caratteri
// 🔹 STEP 6: Create Campioni (Samples) for each part
$campioni = [];
$logContentStep6 = "";
foreach ($parts as $index => $part) {
$matriceId = (int) ($part["idmatrice"] ?? 0);
if ($matriceId <= 0) {
throw new Exception("Invalid or missing idmatrice for part: " . ($part["part_number"] ?? "Unknown"));
}
$campionePayload = [
"Commessa" => $commessaId,
"Matrice" => $matriceId,
"SottoMatrice" => null,
"SchemaCustomField" => $schemaId,
// "Riferimento" => $part["part_description"] ?? "",
"NoteWeb" => $part["part_description"] ?? "",
"ConsegnaRichiesta" => !empty($part["dateexpiry"]) ? $part["dateexpiry"] : $consegnaRichiesta,
];
// Costruisci curl-like per questo campione
$jsonPayload = json_encode($campionePayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep6 .= "CAMPIONE #{$index}\n" .
"curl --location --request POST '{$apiBaseUrl}Campione' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'\n\n";
$campione = $api->post("Campione", $campionePayload);
$logContentStep6 .= "RESPONSE:\n" . json_encode($campione, JSON_PRETTY_PRINT) . "\n\n---\n";
$campione["PartNumber"] = $part["part_number"] ?? "";
$campione["Material"] = $part["material"] ?? "";
$campione["Color"] = $part["color"] ?? "";
$campione["Mix"] = $part["mix"] ?? "";
$campioni[] = $campione;
}
// Salva log per STEP 6
$logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt";
$writeLog($logFileStep6, $logContentStep6, "STEP 6 - Campioni (commessa={$commessaId})");
// 🔹 STEP 6.0: PATCH each Campione custom fields:
// - field 189 (Tested Component) = part_description
// - additional fields from identification_parts_customfields (field_id → value_id/value_text)
$logContentStep63 = "";
foreach ($campioni as $index => $campione) {
$campioneId = (int)($campione['IdCampione'] ?? 0);
$partDescription = $parts[$index]['part_description'] ?? '';
$partId = (int)($parts[$index]['part_id'] ?? 0);
if ($campioneId <= 0) {
continue;
}
// Build a map of overrides: IdCustomField => value
$overrides = [];
// Override 1: Tested Component (field 189) = part_description
if ($partDescription !== '') {
$overrides[189] = $partDescription;
}
// Override 2: values from identification_parts_customfields
$partCFs = $partsCustomFields[$partId] ?? [];
foreach ($partCFs as $pcf) {
$cfFieldId = (int)$pcf['field_id'];
$cfValue = $pcf['value_text'] ?? $pcf['value_id'] ?? null;
if ($cfFieldId > 0 && $cfValue !== null && $cfValue !== '') {
$overrides[$cfFieldId] = (string)$cfValue;
}
}
// Skip if nothing to override
if (empty($overrides)) {
continue;
}
// GET campione custom fields
$campioneWithFields = $api->get("Campione({$campioneId})?\$expand=CampioniCustomFields(\$expand=CustomField)");
$logContentStep63 .= "GET Campione({$campioneId}) CustomFields:\n" .
json_encode($campioneWithFields['CampioniCustomFields'] ?? [], JSON_PRETTY_PRINT) . "\n\n";
$logContentStep63 .= "Overrides for part {$partId}: " . json_encode($overrides) . "\n\n";
// Build PATCH payload — apply overrides where IdCustomField matches
$campioniCustomFields = [];
foreach ($campioneWithFields["CampioniCustomFields"] ?? [] as $cf) {
$definitionId = (int)($cf["CustomField"]["IdCustomField"] ?? 0);
$fieldInstanceId = (int)$cf["IdCampioniCustomFields"];
$currentValue = $cf["Valore"] ?? '';
$newValue = $overrides[$definitionId] ?? $currentValue;
$campioniCustomFields[] = [
"IdCampioniCustomFields" => $fieldInstanceId,
"Valore" => $newValue
];
}
if (!empty($campioniCustomFields)) {
$patchPayload = ["CampioniCustomFields" => $campioniCustomFields];
$patchJson = json_encode($patchPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep63 .= "PATCH Campione({$campioneId}):\n" .
"curl --location --request PATCH '{$apiBaseUrl}Campione({$campioneId})' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$patchJson}'\n\n";
$patchResult = $api->patch("Campione({$campioneId})", $patchPayload);
$logContentStep63 .= "RESPONSE:\n" . json_encode($patchResult, JSON_PRETTY_PRINT) . "\n\n---\n";
}
}
$logFileStep63 = $logDir . "commessa_{$commessaId}_campioni_customfields_step60_" . time() . ".txt";
$writeLog($logFileStep63, $logContentStep63, "STEP 6.0 - Campioni CustomFields (commessa={$commessaId})");
// 🔹 STEP 6.1: Fetch photos linked to this iddatadb
$stmtPhotos = $pdo->prepare("
SELECT id, file_path, file_name, StampaNelRapporto, PrimaPagina
FROM datadb_photos
WHERE iddatadb = :iddatadb
ORDER BY id ASC
");
$stmtPhotos->execute(['iddatadb' => $iddatadb]);
$photos = $stmtPhotos->fetchAll(PDO::FETCH_ASSOC);
// 🔹 STEP 6.2: Upload photos to the first (main) Campione only
$photosUploaded = 0;
$logContentPhotos = "Photos for CommessaWeb {$commessaId} (iddatadb={$iddatadb}):\n";
$logContentPhotos .= "Total photos found: " . count($photos) . ", campioni: " . count($campioni) . "\n\n";
if (!empty($campioni) && !empty($photos)) {
$mainCampione = $campioni[0];
$campioneId = (int)($mainCampione['IdCampione'] ?? 0);
if ($campioneId > 0) {
$logContentPhotos .= "=== Campione {$campioneId} (main) ===\n";
foreach ($photos as $photo) {
$photoPath = $uploadDir . '/' . ltrim($photo['file_path'], './');
$fullPath = realpath($photoPath);
if (!$fullPath || !file_exists($fullPath)) {
$logContentPhotos .= "SKIP (file not found): {$photoPath}\n";
continue;
}
$photoEndpoint = "Campione({$campioneId})/UploadCampioneFile";
$stampaNelRapporto = !empty($photo['StampaNelRapporto']);
$primaPagina = !empty($photo['PrimaPagina']);
$logContentPhotos .= "curl --location --request POST '{$apiBaseUrl}{$photoEndpoint}' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--form 'file=@{$fullPath}'\n\n";
// Step 1: Upload file (flags are ignored by API during upload)
$photoResult = $api->postMultipart($photoEndpoint, $fullPath, $photo['file_name']);
$logContentPhotos .= "UPLOAD RESPONSE:\n" . json_encode($photoResult, JSON_PRETTY_PRINT) . "\n\n";
// Step 2: PATCH CampioneFile to set flags (StampaNelRapporto, PrimaPagina)
$campioneFileId = (int)($photoResult['IdCampioneFile'] ?? 0);
if ($campioneFileId > 0 && ($stampaNelRapporto || $primaPagina)) {
$patchPayload = [];
if ($stampaNelRapporto) {
$patchPayload['StampaNelRapporto'] = true;
}
if ($primaPagina) {
$patchPayload['PrimaPagina'] = true;
}
$patchEndpoint = "CampioneFile({$campioneFileId})";
$patchJsonLog = json_encode($patchPayload, JSON_PRETTY_PRINT);
$logContentPhotos .= "curl --location --request PATCH '{$apiBaseUrl}{$patchEndpoint}' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$patchJsonLog}'\n\n";
$patchResult = $api->patch($patchEndpoint, $patchPayload);
$logContentPhotos .= "PATCH RESPONSE:\n" . json_encode($patchResult, JSON_PRETTY_PRINT) . "\n\n";
}
$logContentPhotos .= "---\n";
$photosUploaded++;
}
} else {
$logContentPhotos .= "SKIP: main campione has invalid IdCampione\n";
}
} elseif (empty($campioni)) {
$logContentPhotos .= "SKIP: no campioni created, cannot upload photos\n";
}
$logFilePhotos = $logDir . "commessa_{$commessaId}_photos_step5_2_" . time() . ".txt";
$writeLog($logFilePhotos, $logContentPhotos, "STEP 6.2 - Photos (commessa={$commessaId})");
// 🔹 STEP 7: Update Custom Fields for CommessaWeb
if (!empty($fieldValues)) {
// GET con espansione per CustomField
$expand = "CommesseCustomFields(\$expand=CustomField)";
$commessaWithFields = $api->get("CommessaWeb({$commessaId})?\$expand={$expand}");
// Logga il GET
$logContentGet = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
"--header 'Authorization: Bearer ••••••'\n\n" .
"RESPONSE:\n" . json_encode($commessaWithFields, JSON_PRETTY_PRINT);
$logFileGet = $logDir . "commessa_{$commessaId}_get_step7_" . time() . ".txt";
$writeLog($logFileGet, $logContentGet, "STEP 7 - GET CustomFields (commessa={$commessaId})");
// Prepara payload PATCH
$commessaCustomFields = [];
foreach ($commessaWithFields["CommesseCustomFields"] as $customField) {
$definitionId = (int) ($customField["CustomField"]["IdCustomField"] ?? 0);
$fieldId = (int) $customField["IdCommesseCustomFields"];
$currentValue = $customField["Valore"] ?? '';
$fieldType = $customField["CustomField"]["Tipo"] ?? '';
$newValue = isset($valueMap[$definitionId]) ? $valueMap[$definitionId] : $currentValue;
// Valida se il campo è di tipo Data
if ($fieldType === 'Data' && $newValue !== $currentValue) {
$newValue = formatDateToExport($newValue);
}
$commessaCustomFields[] = [
"IdCommesseCustomFields" => $fieldId,
"Valore" => $newValue
];
}
$logFileStep7 = null;
if (!empty($commessaCustomFields)) {
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields];
// Logga payload e response
$jsonPayload = json_encode($updatePayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep7 = "curl --location --request PATCH '{$apiBaseUrl}CommessaWeb({$commessaId})' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'";
$patchResponse = $api->patch("CommessaWeb({$commessaId})", $updatePayload);
$logContentStep7 .= "\n\nRESPONSE:\n" . json_encode($patchResponse, JSON_PRETTY_PRINT);
$logFileStep7 = $logDir . "commessa_{$commessaId}_update_step7_" . time() . ".txt";
$writeLog($logFileStep7, $logContentStep7, "STEP 7 - PATCH CustomFields (commessa={$commessaId})");
}
}
// 🔹 STEP 8: Update datadb with idcommessaweb, commessaweb, and status
$stmt = $pdo->prepare("
UPDATE datadb
SET idcommessaweb = :idcommessaweb, commessaweb = :commessaweb, status = 'l'
WHERE iddatadb = :iddatadb
");
$stmt->execute([
'idcommessaweb' => $commessaId,
'commessaweb' => $commessaWebCode,
'iddatadb' => $iddatadb
]);
// 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto)
$sendResult = $api->post("CommessaWeb({$commessaId})/InviaCommessa", []);
// Logga il POST
$logContentStep9 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/InviaCommessa' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{}'\n\n" .
"RESPONSE:\n" . json_encode($sendResult, JSON_PRETTY_PRINT);
$logFileStep9 = $logDir . "commessa_{$commessaId}_send_step9_" . time() . ".txt";
$writeLog($logFileStep9, $logContentStep9, "STEP 9 - InviaCommessa (commessa={$commessaId})");
// 🔹 STEP 9.5: Importazione da CommessaWeb a Commessa (commentato come richiesto)
// Supplier call: POST api/odata/CommessaWeb(XXX)/ImportaCommessa
$importPayload = ["IdUtente" => 285]; // user-id
$importResult = $api->post("CommessaWeb({$commessaId})/ImportaCommessa", $importPayload);
$importPayloadLog = json_encode($importPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
// Logga il POST
$logContentStep91 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/ImportaCommessa' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$importPayloadLog}'\n\n" .
"RESPONSE:\n" . json_encode($importResult, JSON_PRETTY_PRINT);
$logFileStep91 = $logDir . "commessa_{$commessaId}_importa_step91_" . time() . ".txt";
$writeLog($logFileStep91, $logContentStep91, "STEP 9.5 - ImportaCommessa (commessa={$commessaId})");
// 🔹 STEP 10: GET di controllo post-PATCH
$expand = "CommesseCustomFields(\$expand=CustomField)";
$commessaAfterPatch = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand);
// Logga il GET di controllo
$logContentStep10 = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
"--header 'Authorization: Bearer ••••••'\n\n" .
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
$writeLog($logFileStep10, $logContentStep10, "STEP 10 - GET verify (commessa={$commessaId})");
// 🔹 STEP 11: Prepare final response
$finalCommessa = [
"Cliente" => $clienteId,
"SchemaCustomField" => $schemaId,
"Richiedente" => $commessaWeb["Richiedente"] ?? "Web Import",
"Descrizione" => $commessaWeb["Descrizione"] ?? "",
"CommesseCustomFields" => $commessaAfterPatch["CommesseCustomFields"] ?? [],
"Campioni" => $campioni,
"Inviata" => 0 // Non inviato, come richiesto
];
echo json_encode([
"success" => true,
"idcommessaweb" => $commessaId,
"commessaweb" => $commessaWebCode,
"commessaWeb" => $finalCommessa,
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
"totalCampioni" => count($campioni),
"totalCustomFields" => count($commessaAfterPatch["CommesseCustomFields"] ?? []),
"totalPhotos" => count($photos),
"message" => "Export successful",
"logFiles" => [
"step5_create" => $logFileStep5,
"step5_2_photos" => $logFilePhotos,
"step6_campioni" => $logFileStep6,
"step7_patch" => $logFileStep7 ?? null,
"step9_1_importa" => $logFileStep91,
"step10_get" => $logFileStep10
]
]);
} catch (Exception $e) {
error_log("LIMS Export Error: " . $e->getMessage() . "\nTrace: " . $e->getTraceAsString());
echo json_encode([
"success" => false,
"message" => "Export failed: " . $e->getMessage(),
"logFiles" => [
"step5_create" => $logFileStep5 ?? null,
"step5_2_photos" => $logFilePhotos ?? null,
"step6_campioni" => $logFileStep6 ?? null,
"step7_patch" => $logFileStep7 ?? null,
"step9_1_importa" => $logFileStep91 ?? null,
"step10_get" => $logFileStep10 ?? null
]
]);
}