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
This commit is contained in:
r.mubarakzyanov 2026-02-28 02:07:40 +03:00
parent 1fed113c5c
commit c7416ba4a9
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).
*
* @param string $endpoint OData endpoint, e.g. "AllegatoCommessaWeb"
* @param string $filePath Absolute path to the file on disk
* @param string $fileName Original file name to send
* @param int $commessaId CommessaWeb ID to link the attachment to
* @return array|null Decoded JSON response
* @param string $endpoint OData endpoint, e.g. "Campione(613388)/UploadCampioneFile"
* @param string $filePath Absolute path to the file on disk
* @param string $fileName Original file name to send
* @return array|null Decoded JSON response
*/
public function postMultipart($endpoint, $filePath, $fileName, $commessaId)
public function postMultipart($endpoint, $filePath, $fileName)
{
$token = $this->getToken();
$url = "{$this->baseUrl}/api/odata/{$endpoint}";
@ -220,9 +219,7 @@ class VisualLimsApiClient
$cfile = new CURLFile($filePath, mime_content_type($filePath) ?: 'application/octet-stream', $fileName);
$payload = [
'IdCommessa' => $commessaId,
'NomeFile' => $fileName,
'file' => $cfile,
'file' => $cfile,
];
$ch = curl_init($url);

View File

@ -126,9 +126,9 @@ class VisualLimsApiClientMock
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];
}

View File

@ -43,7 +43,8 @@ try {
d.moltiplicatore_prezzo_id,
d.anagrafica_certest_object_id,
d.anagrafica_certest_service_id,
d.cliente_fornitore_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
@ -65,6 +66,7 @@ try {
$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;
$consegnaRichiesta = !empty($result['consegna_richiesta']) ? $result['consegna_richiesta'] : null;
// 🔹 STEP 3: Fetch Parts (including idmatrice)
$stmt = $pdo->prepare("
@ -108,19 +110,20 @@ try {
// 🔹 Initialize API client
$api = VisualLimsApiClient::getInstance();
// 🔹 STEP 5: Create CommessaWeb (NOT WebOrder)
// Includes fixed fields fetched from datadb in STEP 1+2
// 🔹 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" => "Test Web Import",
"Descrizione" => "TEST CommessaWeb",
// Fixed fields from datadb
"ClienteResponsabile" => $clienteResponsabile,
"MoltiplicatorePrezzo" => $moltiplicatorePrezzo,
"AnagraficaCertestObject" => $anagraficaObject,
"AnagraficaCertestService" => $anagraficaService,
"ClienteFornitore" => $clienteFornitore, // PLACEHOLDER — to be implemented
"Cliente" => $clienteId,
"SchemaCustomField" => $schemaId,
"Richiedente" => "Test Web Import", // TODO: replace with real value
"Descrizione" => "TEST CommessaWeb", // TODO: replace with real value
"CustomerManager" => $clienteResponsabile,
"PriceMultiplier" => $moltiplicatorePrezzo,
"CertestObjectMasterData" => $anagraficaObject,
"CertestServiceMasterData" => $anagraficaService,
"CustomerSupplier" => $clienteFornitore, // PLACEHOLDER — to be implemented
// DeliveryRequest goes to Campione, not CommessaWeb
];
// Costruisci log curl-like per STEP 5
@ -141,49 +144,6 @@ try {
$commessaId = $commessaWeb["IdCommessa"];
$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
$campioni = [];
$logContentStep6 = "";
@ -196,11 +156,12 @@ try {
}
$campionePayload = [
"Commessa" => $commessaId,
"Matrice" => $matriceId,
"SottoMatrice" => null,
"Commessa" => $commessaId,
"Matrice" => $matriceId,
"SottoMatrice" => null,
"SchemaCustomField" => $schemaId,
"NoteWeb" => $part["part_description"] ?? ""
"NoteWeb" => $part["part_description"] ?? "",
"DeliveryRequest" => $consegnaRichiesta,
];
// Costruisci curl-like per questo campione
@ -227,11 +188,62 @@ try {
$logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt";
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 each Campione
// Photos document the overall test, so all photos are attached to every campione.
$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)) {
foreach ($campioni as $campione) {
$campioneId = (int)($campione['IdCampione'] ?? 0);
if ($campioneId <= 0) continue;
$logContentPhotos .= "=== Campione {$campioneId} ===\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++;
}
}
} 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
if (!empty($fieldValues)) {
// GET con espansione per CustomField
$expand = "CommesseCustomFields(\$expand=CustomField)";
$commessaWithFields = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand);
$commessaWithFields = $api->get("CommessaWeb({$commessaId})?\$expand={$expand}");
// Logga il GET
$logContentGet = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
@ -260,6 +272,7 @@ try {
];
}
$logFileStep7 = null;
if (!empty($commessaCustomFields)) {
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields];