Compare commits

...

2 Commits

Author SHA1 Message Date
a626c8283e upload photos to main campione only 2026-02-28 15:48:19 +03:00
c7416ba4a9 fix photo upload endpoint and align CommessaWeb field names with API docs
- CommessaWeb POST: rename fields per documentation — CustomerManager, PriceMultiplier, CertestObjectMasterData, CertestServiceMasterData, CustomerSupplier
- Move DeliveryRequest (ConsegnaRichiesta) from CommessaWeb to Campione
- Photo upload: change endpoint from AllegatoCommessaWeb to Campione({id})/UploadCampioneFile, upload to all campioni
- postMultipart(): remove commessaId param, send only file field
2026-02-28 02:07:40 +03:00
3 changed files with 82 additions and 72 deletions

View File

@ -206,13 +206,12 @@ class VisualLimsApiClient
/** /**
* POST a file as multipart/form-data (used for photo/attachment uploads). * POST a file as multipart/form-data (used for photo/attachment uploads).
* *
* @param string $endpoint OData endpoint, e.g. "AllegatoCommessaWeb" * @param string $endpoint OData endpoint, e.g. "Campione(613388)/UploadCampioneFile"
* @param string $filePath Absolute path to the file on disk * @param string $filePath Absolute path to the file on disk
* @param string $fileName Original file name to send * @param string $fileName Original file name to send
* @param int $commessaId CommessaWeb ID to link the attachment to * @return array|null Decoded JSON response
* @return array|null Decoded JSON response
*/ */
public function postMultipart($endpoint, $filePath, $fileName, $commessaId) public function postMultipart($endpoint, $filePath, $fileName)
{ {
$token = $this->getToken(); $token = $this->getToken();
$url = "{$this->baseUrl}/api/odata/{$endpoint}"; $url = "{$this->baseUrl}/api/odata/{$endpoint}";
@ -220,9 +219,7 @@ class VisualLimsApiClient
$cfile = new CURLFile($filePath, mime_content_type($filePath) ?: 'application/octet-stream', $fileName); $cfile = new CURLFile($filePath, mime_content_type($filePath) ?: 'application/octet-stream', $fileName);
$payload = [ $payload = [
'IdCommessa' => $commessaId, 'file' => $cfile,
'NomeFile' => $fileName,
'file' => $cfile,
]; ];
$ch = curl_init($url); $ch = curl_init($url);

View File

@ -126,9 +126,9 @@ class VisualLimsApiClientMock
return []; return [];
} }
public function postMultipart(string $endpoint, string $filePath, string $fileName, int $commessaId): array public function postMultipart(string $endpoint, string $filePath, string $fileName): array
{ {
error_log("[SIMULATE] POST multipart {$endpoint} file={$fileName} commessaId={$commessaId}"); error_log("[SIMULATE] POST multipart {$endpoint} file={$fileName}");
return ['simulated' => true, 'file' => $fileName]; return ['simulated' => true, 'file' => $fileName];
} }

View File

@ -43,7 +43,8 @@ try {
d.moltiplicatore_prezzo_id, d.moltiplicatore_prezzo_id,
d.anagrafica_certest_object_id, d.anagrafica_certest_object_id,
d.anagrafica_certest_service_id, d.anagrafica_certest_service_id,
d.cliente_fornitore_id d.cliente_fornitore_id,
d.consegna_richiesta
FROM datadb as d FROM datadb as d
INNER JOIN excel_templates as et ON d.templateid = et.id INNER JOIN excel_templates as et ON d.templateid = et.id
WHERE d.iddatadb = :iddatadb WHERE d.iddatadb = :iddatadb
@ -65,6 +66,7 @@ try {
$anagraficaObject = !empty($result['anagrafica_certest_object_id']) ? (int) $result['anagrafica_certest_object_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; $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; $clienteFornitore = !empty($result['cliente_fornitore_id'])? (int) $result['cliente_fornitore_id']: null;
$consegnaRichiesta = !empty($result['consegna_richiesta']) ? $result['consegna_richiesta'] : null;
// 🔹 STEP 3: Fetch Parts (including idmatrice) // 🔹 STEP 3: Fetch Parts (including idmatrice)
$stmt = $pdo->prepare(" $stmt = $pdo->prepare("
@ -108,19 +110,20 @@ try {
// 🔹 Initialize API client // 🔹 Initialize API client
$api = VisualLimsApiClient::getInstance(); $api = VisualLimsApiClient::getInstance();
// 🔹 STEP 5: Create CommessaWeb (NOT WebOrder) // 🔹 STEP 5: Create CommessaWeb
// Includes fixed fields fetched from datadb in STEP 1+2 // 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 = [ $commessaWebPayload = [
"Cliente" => $clienteId, "Cliente" => $clienteId,
"SchemaCustomField" => $schemaId, "SchemaCustomField" => $schemaId,
"Richiedente" => "Test Web Import", "Richiedente" => "Test Web Import", // TODO: replace with real value
"Descrizione" => "TEST CommessaWeb", "Descrizione" => "TEST CommessaWeb", // TODO: replace with real value
// Fixed fields from datadb "CustomerManager" => $clienteResponsabile,
"ClienteResponsabile" => $clienteResponsabile, "PriceMultiplier" => $moltiplicatorePrezzo,
"MoltiplicatorePrezzo" => $moltiplicatorePrezzo, "CertestObjectMasterData" => $anagraficaObject,
"AnagraficaCertestObject" => $anagraficaObject, "CertestServiceMasterData" => $anagraficaService,
"AnagraficaCertestService" => $anagraficaService, "CustomerSupplier" => $clienteFornitore, // PLACEHOLDER — to be implemented
"ClienteFornitore" => $clienteFornitore, // PLACEHOLDER — to be implemented // DeliveryRequest goes to Campione, not CommessaWeb
]; ];
// Costruisci log curl-like per STEP 5 // Costruisci log curl-like per STEP 5
@ -141,49 +144,6 @@ try {
$commessaId = $commessaWeb["IdCommessa"]; $commessaId = $commessaWeb["IdCommessa"];
$commessaWebCode = substr($commessaWeb["CodiceCommessa"] ?? "TEST CommessaWeb", 0, 30); // Limite a 30 caratteri $commessaWebCode = substr($commessaWeb["CodiceCommessa"] ?? "TEST CommessaWeb", 0, 30); // Limite a 30 caratteri
// 🔹 STEP 5.1: Fetch photos linked to this iddatadb
$stmtPhotos = $pdo->prepare("
SELECT id, file_path, file_name
FROM datadb_photos
WHERE iddatadb = :iddatadb
ORDER BY id ASC
");
$stmtPhotos->execute(['iddatadb' => $iddatadb]);
$photos = $stmtPhotos->fetchAll(PDO::FETCH_ASSOC);
// 🔹 STEP 5.2: Upload photos to CommessaWeb
// NOTE: The sample number corresponds to the CommessaWeb ID ($commessaId).
// Photos may be multiple or may not exist at all.
$photosUploaded = 0;
$logContentPhotos = "Photos for CommessaWeb {$commessaId} (iddatadb={$iddatadb}):\n";
$logContentPhotos .= "Total photos found: " . count($photos) . "\n\n";
foreach ($photos as $photo) {
// Build absolute path from the relative path stored in DB
$photoPath = $uploadDir . '/' . ltrim($photo['file_path'], './');
$fullPath = realpath($photoPath);
if (!$fullPath || !file_exists($fullPath)) {
$logContentPhotos .= "SKIP (file not found): full - $photoPath " . $photo['file_path'] . "\n";
continue;
}
// Construct curl-like log entry
$logContentPhotos .= "curl --location --request POST '{$apiBaseUrl}AllegatoCommessaWeb' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--form 'IdCommessa={$commessaId}' \\\n" .
"--form 'file=@{$fullPath}'\n\n";
// ENDPOINT NAME TO BE CONFIRMED
$photoResult = $api->postMultipart("AllegatoCommessaWeb", $fullPath, $photo['file_name'], $commessaId);
$logContentPhotos .= "RESPONSE:\n" . json_encode($photoResult, JSON_PRETTY_PRINT) . "\n\n---\n";
$photosUploaded++;
}
$logFilePhotos = $logDir . "commessa_{$commessaId}_photos_step5_2_" . time() . ".txt";
file_put_contents($logFilePhotos, $logContentPhotos);
// 🔹 STEP 6: Create Campioni (Samples) for each part // 🔹 STEP 6: Create Campioni (Samples) for each part
$campioni = []; $campioni = [];
$logContentStep6 = ""; $logContentStep6 = "";
@ -196,11 +156,12 @@ try {
} }
$campionePayload = [ $campionePayload = [
"Commessa" => $commessaId, "Commessa" => $commessaId,
"Matrice" => $matriceId, "Matrice" => $matriceId,
"SottoMatrice" => null, "SottoMatrice" => null,
"SchemaCustomField" => $schemaId, "SchemaCustomField" => $schemaId,
"NoteWeb" => $part["part_description"] ?? "" "NoteWeb" => $part["part_description"] ?? "",
"DeliveryRequest" => $consegnaRichiesta,
]; ];
// Costruisci curl-like per questo campione // Costruisci curl-like per questo campione
@ -227,11 +188,62 @@ try {
$logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt"; $logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt";
file_put_contents($logFileStep6, $logContentStep6); file_put_contents($logFileStep6, $logContentStep6);
// 🔹 STEP 6.1: Fetch photos linked to this iddatadb
$stmtPhotos = $pdo->prepare("
SELECT id, file_path, file_name
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";
$logContentPhotos .= "curl --location --request POST '{$apiBaseUrl}{$photoEndpoint}' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--form 'file=@{$fullPath}'\n\n";
$photoResult = $api->postMultipart($photoEndpoint, $fullPath, $photo['file_name']);
$logContentPhotos .= "RESPONSE:\n" . json_encode($photoResult, JSON_PRETTY_PRINT) . "\n\n---\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";
file_put_contents($logFilePhotos, $logContentPhotos);
// 🔹 STEP 7: Update Custom Fields for CommessaWeb // 🔹 STEP 7: Update Custom Fields for CommessaWeb
if (!empty($fieldValues)) { if (!empty($fieldValues)) {
// GET con espansione per CustomField // GET con espansione per CustomField
$expand = "CommesseCustomFields(\$expand=CustomField)"; $expand = "CommesseCustomFields(\$expand=CustomField)";
$commessaWithFields = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand); $commessaWithFields = $api->get("CommessaWeb({$commessaId})?\$expand={$expand}");
// Logga il GET // Logga il GET
$logContentGet = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" . $logContentGet = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
@ -260,6 +272,7 @@ try {
]; ];
} }
$logFileStep7 = null;
if (!empty($commessaCustomFields)) { if (!empty($commessaCustomFields)) {
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields]; $updatePayload = ["CommesseCustomFields" => $commessaCustomFields];