Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3ce489348 | |||
| 08b89e01cc | |||
| 490786731a | |||
| e96f538a47 | |||
| cc96ecb67f | |||
| 4cf03ae742 | |||
| 7a486e9dcf | |||
| a05d9fed2b | |||
| 65170a0a7c | |||
| 223688c372 | |||
| b562eb4033 | |||
| 0645a0c675 | |||
| a02a6b2c4c | |||
| 45dd8d6907 | |||
| 755f6812d4 | |||
| 5e59ae2162 | |||
| 71a19144c8 | |||
| 381a05341b | |||
| 5a58decd40 | |||
| eb21910ef3 | |||
| 5dedc779df | |||
| f4e0074a73 | |||
| 9c850e4ea6 | |||
| f300811341 | |||
| 48387a9945 | |||
| 0e90db8219 | |||
| eaf70d5a46 | |||
| cdd6551e9c | |||
| 1b97bf4362 | |||
| c516589483 | |||
| 817bbadf22 | |||
| 1f27bc48d4 | |||
| c9fba48d88 | |||
| 70d4c0759e | |||
| 5d7880160a | |||
| bbe74d1529 | |||
| 93930227a2 | |||
| 2598a4c91b | |||
| 5e677a8b9c | |||
| 540c44d89a | |||
| 2ee9f2ecb1 | |||
| c9122774b1 | |||
| 1fed113c5c | |||
| e3994d6f9f | |||
| 9af0df3cca | |||
| 48d2a3ff42 | |||
| cf44e67922 | |||
| 35021e9d9b | |||
| 497ebda65a | |||
| b0024edb70 | |||
| b9852ba226 | |||
| 407d6884a1 | |||
| 1a4beadbb2 | |||
| 4bb0445cff | |||
| 73dd8f4ce8 | |||
| bdc4e0e60c | |||
| ef8f2d8000 | |||
| 74c9a1d02a | |||
| cd3bccd183 | |||
| 78154e43a9 | |||
| 9fe9243e60 | |||
| a8330d4aba | |||
| 82d6a2ee18 | |||
| d8eddb3aa5 | |||
| f60dc64b2d | |||
| 4e4cae1df8 | |||
| 8838edf3a1 | |||
| e75be99e43 | |||
| a482d975da | |||
| 598a2cc84c | |||
| 6ec0c2062e | |||
| 5eb5bd1613 | |||
| 03771e3ca8 | |||
| 03642fdfab | |||
| f6ea17388c | |||
| 1c2b4ab7a6 | |||
| 31cb23b00e | |||
| d29563d20d | |||
| 82af925ac1 | |||
| 5d8360dd87 | |||
| 683073c244 |
+7
-18
@@ -7,9 +7,9 @@ LOG_CHANNEL=stack
|
|||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST="localhost"
|
DB_HOST="localhost"
|
||||||
DB_DATABASE="trfcertest"
|
DB_DATABASE="xxxx"
|
||||||
DB_USERNAME="solocla"
|
DB_USERNAME="xxxx"
|
||||||
DB_PASSWORD="xxxxxxx"
|
DB_PASSWORD="xxxxx"
|
||||||
DB_PREFIX="auth_"
|
DB_PREFIX="auth_"
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
@@ -41,19 +41,8 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
|||||||
|
|
||||||
# Credenziali API VisualLims
|
# Credenziali API VisualLims
|
||||||
SIMULATE_EXPORT_LIMS=true
|
SIMULATE_EXPORT_LIMS=true
|
||||||
API_BASE_URL=https://93.43.5.102/limsapi
|
API_BASE_URL=https://bvcpsitaly-elims.com/limsapi
|
||||||
API_USERNAME=xxxx
|
API_USERNAME=WebApiUser
|
||||||
API_PASSWORD=XXXX
|
API_PASSWORD=webapiuser01
|
||||||
|
|
||||||
BASE_URL=http://localhost:8000/userarea/
|
BASE_URL=http://localhost:8000/userarea/
|
||||||
|
|
||||||
# Credenziali ENTRAID
|
|
||||||
|
|
||||||
AZURE_CLIENT_ID=your-client-id
|
|
||||||
AZURE_CLIENT_SECRET=your-client-secret
|
|
||||||
AZURE_REDIRECT_URI=https://your-app.com/auth/azure/callback
|
|
||||||
AZURE_TENANT_ID=
|
|
||||||
|
|
||||||
MICROSOFT_CLIENT_ID=your_client_id_here
|
|
||||||
MICROSOFT_CLIENT_SECRET=your_client_secret_here
|
|
||||||
MICROSOFT_REDIRECT_URI="${APP_URL}/auth/microsoft/callback"
|
|
||||||
+34
-43
@@ -1,66 +1,57 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
/node_modules
|
/node_modules
|
||||||
/public/hot
|
|
||||||
/public/storage
|
|
||||||
/storage/*.key
|
|
||||||
/vendor
|
/vendor
|
||||||
|
|
||||||
/.idea
|
/.idea
|
||||||
/.fleet
|
/.fleet
|
||||||
/.vscode
|
/.vscode
|
||||||
/.vagrant
|
/.vagrant
|
||||||
Homestead.json
|
|
||||||
Homestead.yaml
|
/public/hot
|
||||||
npm-debug.log
|
/public/storage
|
||||||
yarn-error.log
|
|
||||||
.env
|
|
||||||
.phpunit.result.cache
|
|
||||||
.php_cs.cache
|
|
||||||
/documentation
|
|
||||||
/.phpunit.cache
|
|
||||||
/public/build
|
/public/build
|
||||||
|
|
||||||
|
/storage/*.key
|
||||||
|
|
||||||
|
.env
|
||||||
.env.backup
|
.env.backup
|
||||||
.env.production
|
.env.production
|
||||||
auth.json
|
auth.json
|
||||||
# File di debug e temporanei JSON e log
|
|
||||||
|
.phpunit.result.cache
|
||||||
|
.php_cs.cache
|
||||||
|
/.phpunit.cache
|
||||||
|
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
/documentation
|
||||||
|
|
||||||
|
# --- Runtime / Debug (userarea) ---
|
||||||
/public/userarea/*.json
|
/public/userarea/*.json
|
||||||
/public/userarea/*.log
|
/public/userarea/*.log
|
||||||
/public/userarea/*.txt
|
/public/userarea/*.txt
|
||||||
|
/public/userarea/*_response.json
|
||||||
# File di log nella sottocartella class
|
/public/userarea/customfield_values_response.json
|
||||||
|
/public/userarea/error_log.txt
|
||||||
|
/public/userarea/import_debug.log
|
||||||
|
/public/userarea/last_url.txt
|
||||||
|
/public/userarea/logaspi/
|
||||||
|
/public/userarea/logs/api/
|
||||||
|
/public/userarea/logs/api/**
|
||||||
|
/public/userarea/photostrf/
|
||||||
/public/userarea/class/*.log
|
/public/userarea/class/*.log
|
||||||
|
/public/userarea/class/curl_auth_debug.log
|
||||||
|
/public/userarea/class/curl_request_debug.log
|
||||||
|
|
||||||
# File XLSX temporanei importati
|
# File XLSX temporanei importati
|
||||||
/public/userarea/imported_trf/*.xlsx
|
/public/userarea/imported_trf/*.xlsx
|
||||||
/public/userarea/xlstemplates/*.xlsx
|
/public/userarea/xlstemplates/*.xlsx
|
||||||
|
|
||||||
# Ignora cartelle di foto generate
|
# Cartelle foto generate
|
||||||
/public/photostrf/
|
/public/photostrf/
|
||||||
/public/photostrf/qrcodes/
|
/public/photostrf/qrcodes/
|
||||||
public/userarea/import_debug.log
|
|
||||||
public/userarea/last_url.txt
|
|
||||||
public/userarea/class/curl_auth_debug.log
|
|
||||||
public/userarea/class/curl_request_debug.log
|
|
||||||
public/userarea/last_url.txt
|
|
||||||
public/userarea/class/curl_auth_debug.log
|
|
||||||
public/userarea/class/curl_request_debug.log
|
|
||||||
|
|
||||||
# Ignora tutti i log
|
# Ignora tutti i log ovunque
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
|
||||||
# Ignora cartella photostrf in public/userarea
|
|
||||||
/public/userarea/photostrf/
|
|
||||||
public/userarea/customfield_values_response.json
|
|
||||||
/public/userarea/logaspi/
|
|
||||||
|
|
||||||
public/userarea/logsapi/campione_762_1.json
|
|
||||||
public/userarea/logsapi/campione_763_1.json
|
|
||||||
public/userarea/logsapi/campione_762_2.json
|
|
||||||
public/userarea/logsapi/campione_763_2.json
|
|
||||||
public/userarea/logsapi/commessaweb_create_762.json
|
|
||||||
public/userarea/logsapi/commessaweb_create_763.json
|
|
||||||
public/userarea/logsapi/commessaweb_customfields_762.json
|
|
||||||
public/userarea/logsapi/commessaweb_customfields_763.json
|
|
||||||
public/userarea/logsapi/commessaweb_invia_762.json
|
|
||||||
public/userarea/logsapi/commessaweb_invia_763.json
|
|
||||||
public/userarea/logsapi/last_auth_url.txt
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
|||||||
|
# DB LOCALE (Windows 11)
|
||||||
|
url=jdbc:mysql://localhost:3306/trfcertest
|
||||||
|
username=solocla
|
||||||
|
password=!Massarosa2
|
||||||
|
driver=com.mysql.cj.jdbc.Driver
|
||||||
|
changeLogFile=liquibase/changelog/db.changelog-master.yaml
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
require_once(__DIR__ . '/include/headscript.php'); // Auth + $iduserlogin + DBHandlerSelect
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
throw new Exception('Invalid request method');
|
||||||
|
}
|
||||||
|
|
||||||
|
$iddatadb = isset($_POST['iddatadb']) ? (int)$_POST['iddatadb'] : 0;
|
||||||
|
|
||||||
|
if ($iddatadb <= 0) {
|
||||||
|
throw new Exception('Missing iddatadb');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Supporta sia singola stringa (con |) che array part_descriptions[]
|
||||||
|
$parts = [];
|
||||||
|
|
||||||
|
if (isset($_POST['part_descriptions']) && is_array($_POST['part_descriptions'])) {
|
||||||
|
$parts = $_POST['part_descriptions'];
|
||||||
|
} else {
|
||||||
|
$raw = isset($_POST['part_description']) ? (string)$_POST['part_description'] : '';
|
||||||
|
// split su "|" per multi-part
|
||||||
|
$parts = preg_split('/\s*\|\s*/', $raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizza: trim + rimuovi vuoti + dedup
|
||||||
|
$cleanParts = [];
|
||||||
|
foreach ($parts as $p) {
|
||||||
|
$p = trim((string)$p);
|
||||||
|
if ($p === '') continue;
|
||||||
|
|
||||||
|
// limita lunghezza come da DB varchar(255)
|
||||||
|
if (mb_strlen($p) > 255) {
|
||||||
|
$p = mb_substr($p, 0, 255);
|
||||||
|
}
|
||||||
|
$cleanParts[] = $p;
|
||||||
|
}
|
||||||
|
$cleanParts = array_values(array_unique($cleanParts));
|
||||||
|
|
||||||
|
if (count($cleanParts) === 0) {
|
||||||
|
throw new Exception('Part description is empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// prende il prossimo part_number per iddatadb
|
||||||
|
$stmtMax = $pdo->prepare("SELECT COALESCE(MAX(part_number), 0) AS maxnum FROM identification_parts WHERE iddatadb = ?");
|
||||||
|
$stmtMax->execute([$iddatadb]);
|
||||||
|
$nextNumber = (int)$stmtMax->fetchColumn() + 1;
|
||||||
|
|
||||||
|
$stmtIns = $pdo->prepare("
|
||||||
|
INSERT INTO identification_parts (iddatadb, part_number, part_description)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
");
|
||||||
|
|
||||||
|
$insertedIds = [];
|
||||||
|
|
||||||
|
foreach ($cleanParts as $p) {
|
||||||
|
$ok = $stmtIns->execute([$iddatadb, $nextNumber, $p]);
|
||||||
|
if (!$ok) {
|
||||||
|
throw new Exception('Insert failed');
|
||||||
|
}
|
||||||
|
$insertedIds[] = $pdo->lastInsertId();
|
||||||
|
$nextNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Parts added',
|
||||||
|
'count' => count($insertedIds),
|
||||||
|
'ids' => $insertedIds
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
+244
-119
@@ -12,12 +12,16 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
let photoAnnotations = {};
|
let photoAnnotations = {};
|
||||||
let partColors = {};
|
let partColors = {};
|
||||||
|
let partSizes = {}; // memorizza la dimensione specifica per parte
|
||||||
let selectedPartNumber = null;
|
let selectedPartNumber = null;
|
||||||
let unsavedChanges = false;
|
let unsavedChanges = false;
|
||||||
let fabricCanvas = null;
|
let fabricCanvas = null;
|
||||||
let descriptionTextbox = null;
|
let descriptionTextbox = null;
|
||||||
let markerObjects = {};
|
let markerObjects = {};
|
||||||
|
let nextMarkerId = 1;
|
||||||
let partsListData = [];
|
let partsListData = [];
|
||||||
|
// DIMENSIONE GLOBALE MARKER
|
||||||
|
let globalMarkerSize = 16;
|
||||||
|
|
||||||
// ===================
|
// ===================
|
||||||
// MODAL INITIALIZATION
|
// MODAL INITIALIZATION
|
||||||
@@ -29,6 +33,8 @@ $(document).ready(function () {
|
|||||||
trfHeader,
|
trfHeader,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#annotationsModal").attr("data-iddatadb", iddatadb);
|
||||||
|
|
||||||
if (!iddatadb && !idquotations) {
|
if (!iddatadb && !idquotations) {
|
||||||
const errorMsg = $(
|
const errorMsg = $(
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Errore: ID TRF mancante. Impossibile inizializzare il modale delle annotazioni.</div>',
|
'<div class="alert alert-danger temp-alert" role="alert">Errore: ID TRF mancante. Impossibile inizializzare il modale delle annotazioni.</div>',
|
||||||
@@ -67,6 +73,9 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
modal.show();
|
modal.show();
|
||||||
|
// Inizializza slider dimensione marker
|
||||||
|
$("#markerSizeSlider").val(globalMarkerSize);
|
||||||
|
$("#markerSizeValue").text(globalMarkerSize + "px");
|
||||||
|
|
||||||
// Debug: Verifica presenza elementi DOM
|
// Debug: Verifica presenza elementi DOM
|
||||||
console.log(
|
console.log(
|
||||||
@@ -128,6 +137,7 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
descriptionTextbox = null;
|
descriptionTextbox = null;
|
||||||
markerObjects = {};
|
markerObjects = {};
|
||||||
|
globalMarkerSize = 16;
|
||||||
$("#photoSelectorContainerAnnotations").empty().hide();
|
$("#photoSelectorContainerAnnotations").empty().hide();
|
||||||
$("#samplePhotoAnnotations").attr("src", "");
|
$("#samplePhotoAnnotations").attr("src", "");
|
||||||
$("#partsListAnnotations").empty();
|
$("#partsListAnnotations").empty();
|
||||||
@@ -144,6 +154,30 @@ $(document).ready(function () {
|
|||||||
$(":focus").blur();
|
$(":focus").blur();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// SLIDER DIMENSIONE MARKER
|
||||||
|
$(document)
|
||||||
|
.off("input", "#markerSizeSlider")
|
||||||
|
.on("input", "#markerSizeSlider", function () {
|
||||||
|
globalMarkerSize = parseInt($(this).val());
|
||||||
|
$("#markerSizeValue").text(globalMarkerSize + "px");
|
||||||
|
|
||||||
|
partsListData.forEach(function (part) {
|
||||||
|
if (part && part.part_number != null) {
|
||||||
|
partSizes[part.part_number] = globalMarkerSize;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#partsListAnnotations .marker-size-slider").val(
|
||||||
|
globalMarkerSize,
|
||||||
|
);
|
||||||
|
$("#partsListAnnotations .marker-size-value").text(
|
||||||
|
globalMarkerSize + "px",
|
||||||
|
);
|
||||||
|
|
||||||
|
updateMarkers();
|
||||||
|
markUnsaved();
|
||||||
|
});
|
||||||
|
|
||||||
// ===================
|
// ===================
|
||||||
// PHOTO LOADERS
|
// PHOTO LOADERS
|
||||||
// ===================
|
// ===================
|
||||||
@@ -347,22 +381,13 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
const partColor =
|
const partColor =
|
||||||
partColors[selectedPartNumber] || "#ff0000";
|
partColors[selectedPartNumber] || "#ff0000";
|
||||||
const existingMarker = photoAnnotations[
|
photoAnnotations[currentPhoto].markers.push({
|
||||||
currentPhoto
|
id: nextMarkerId++,
|
||||||
].markers.find((m) => m.partNumber == selectedPartNumber);
|
partNumber: selectedPartNumber,
|
||||||
|
x,
|
||||||
if (existingMarker) {
|
y,
|
||||||
existingMarker.x = x;
|
color: partColor,
|
||||||
existingMarker.y = y;
|
});
|
||||||
existingMarker.color = partColor;
|
|
||||||
} else {
|
|
||||||
photoAnnotations[currentPhoto].markers.push({
|
|
||||||
partNumber: selectedPartNumber,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
color: partColor,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Marker aggiunto/spostato:", {
|
console.log("Marker aggiunto/spostato:", {
|
||||||
partNumber: selectedPartNumber,
|
partNumber: selectedPartNumber,
|
||||||
@@ -372,8 +397,6 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
updateMarkers();
|
updateMarkers();
|
||||||
markUnsaved();
|
markUnsaved();
|
||||||
selectedPartNumber = null;
|
|
||||||
$("#partsListAnnotations li").removeClass("active");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fabricCanvas.upperCanvasEl.focus();
|
fabricCanvas.upperCanvasEl.focus();
|
||||||
@@ -465,113 +488,89 @@ $(document).ready(function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// ===================
|
// ===================
|
||||||
// BACK TO PARTS MODAL
|
// TORNA AL MODALE PARTI (modal_partsTable.php)
|
||||||
// ===================
|
// ===================
|
||||||
$(document)
|
$(document)
|
||||||
.off("click.backToParts", "#backToPartsBtnAnnotations")
|
.off("click.backToParts", "#backToPartsBtnAnnotations")
|
||||||
.on("click.backToParts", "#backToPartsBtnAnnotations", function (e) {
|
.on("click.backToParts", "#backToPartsBtnAnnotations", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
console.log(
|
|
||||||
"Evento click su #backToPartsBtnAnnotations, ID elemento:",
|
|
||||||
$(this).attr("id"),
|
|
||||||
);
|
|
||||||
if (!$("#backToPartsBtnAnnotations").length) {
|
|
||||||
console.error(
|
|
||||||
"Pulsante #backToPartsBtnAnnotations non trovato nel DOM.",
|
|
||||||
);
|
|
||||||
const errorMsg = $(
|
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Errore: Pulsante #backToPartsBtnAnnotations non trovato nel DOM.</div>',
|
|
||||||
);
|
|
||||||
$("#annotationsModal .modal-body").prepend(errorMsg);
|
|
||||||
setTimeout(function () {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controlla modifiche non salvate
|
|
||||||
if (
|
if (
|
||||||
unsavedChanges &&
|
unsavedChanges &&
|
||||||
!confirm(
|
!confirm(
|
||||||
"Hai modifiche non salvate. Vuoi davvero tornare al modale delle parti?",
|
"Hai modifiche non salvate. Vuoi davvero tornare al modale delle parti?",
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
console.log(
|
|
||||||
"Tornare al modale delle parti annullato a causa di modifiche non salvate.",
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chiudi annotationsModal
|
|
||||||
const annotationsModalElement =
|
|
||||||
document.getElementById("annotationsModal");
|
|
||||||
const annotationsModal = bootstrap.Modal.getInstance(
|
|
||||||
annotationsModalElement,
|
|
||||||
);
|
|
||||||
if (annotationsModal) {
|
|
||||||
annotationsModal.hide();
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
"Impossibile trovare l'istanza del modale #annotationsModal.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apri partsModal
|
|
||||||
const iddatadb = $("#annotationsModal").data("iddatadb");
|
const iddatadb = $("#annotationsModal").data("iddatadb");
|
||||||
const idquotations = $("#annotationsModal").data("idquotations");
|
const idquotations = $("#annotationsModal").data("idquotations");
|
||||||
const trfHeader = $("#trfHeaderAnnotations").text();
|
const trfHeader = $("#trfHeaderAnnotations").text();
|
||||||
console.log("Apertura partsModal con:", {
|
|
||||||
|
// CHIUDI MODALE ANNOTAZIONI IN MODO SICURO
|
||||||
|
const annotationsModalElement =
|
||||||
|
document.getElementById("annotationsModal");
|
||||||
|
if (annotationsModalElement) {
|
||||||
|
const modalInstance = bootstrap.Modal.getInstance(
|
||||||
|
annotationsModalElement,
|
||||||
|
);
|
||||||
|
if (modalInstance) {
|
||||||
|
modalInstance.hide();
|
||||||
|
} else {
|
||||||
|
$(annotationsModalElement).modal("hide"); // fallback jQuery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("Torno a modal_partsTable.php con:", {
|
||||||
iddatadb,
|
iddatadb,
|
||||||
idquotations,
|
idquotations,
|
||||||
trfHeader,
|
trfHeader,
|
||||||
});
|
});
|
||||||
|
// CARICA E APRI MODALE PARTI
|
||||||
|
$.get(
|
||||||
|
"modal_partsTable.php",
|
||||||
|
{
|
||||||
|
iddatadb: iddatadb || "",
|
||||||
|
idquotations: idquotations || "",
|
||||||
|
trfHeader: trfHeader,
|
||||||
|
},
|
||||||
|
function (data) {
|
||||||
|
// Rimuovi vecchio modale (con ID corretto)
|
||||||
|
$("#partsTableModal").remove();
|
||||||
|
$(".modal-backdrop").remove();
|
||||||
|
|
||||||
const partsModalElement = document.getElementById("partsModal");
|
// Aggiungi nuovo modale
|
||||||
if (!partsModalElement) {
|
$("body").append(data);
|
||||||
console.error("Elemento #partsModal non trovato nel DOM.");
|
|
||||||
const errorMsg = $(
|
// Apri con Bootstrap 5
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Errore: Il modale delle parti non è presente nel DOM.</div>',
|
const partsModalElement =
|
||||||
|
document.getElementById("partsTableModal");
|
||||||
|
if (partsModalElement) {
|
||||||
|
const modal = new bootstrap.Modal(partsModalElement, {
|
||||||
|
backdrop: true,
|
||||||
|
keyboard: true,
|
||||||
|
focus: true,
|
||||||
|
});
|
||||||
|
modal.show();
|
||||||
|
} else {
|
||||||
|
let iddatadb =
|
||||||
|
$("#annotationsModal").attr("data-iddatadb");
|
||||||
|
|
||||||
|
$(
|
||||||
|
"button.parts-btn[data-iddatadb='" +
|
||||||
|
iddatadb +
|
||||||
|
"']",
|
||||||
|
).trigger("click");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
).fail(function (xhr) {
|
||||||
|
console.error("Errore caricamento modale parti:", xhr);
|
||||||
|
alert(
|
||||||
|
"Errore 404: modal_partsTable.php non trovato o errore server.",
|
||||||
);
|
);
|
||||||
$("#annotationsModal .modal-body").prepend(errorMsg);
|
});
|
||||||
setTimeout(function () {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let partsModal = bootstrap.Modal.getInstance(partsModalElement);
|
|
||||||
if (!partsModal) {
|
|
||||||
partsModal = new bootstrap.Modal(partsModalElement, {
|
|
||||||
backdrop: true,
|
|
||||||
keyboard: true,
|
|
||||||
focus: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inizializza il modale delle parti
|
|
||||||
if (typeof window.initPartsModal === "function") {
|
|
||||||
window.initPartsModal(iddatadb, idquotations, trfHeader);
|
|
||||||
partsModal.show();
|
|
||||||
console.log("partsModal aperto con successo.");
|
|
||||||
} else {
|
|
||||||
console.error("Funzione initPartsModal non definita.");
|
|
||||||
const errorMsg = $(
|
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Errore: Funzione initPartsModal non trovata.</div>',
|
|
||||||
);
|
|
||||||
$("#annotationsModal .modal-body").prepend(errorMsg);
|
|
||||||
setTimeout(function () {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===================
|
// ===================
|
||||||
// PARTS LIST
|
// PARTS LIST
|
||||||
// ===================
|
// ===================
|
||||||
@@ -633,12 +632,19 @@ $(document).ready(function () {
|
|||||||
)
|
)
|
||||||
.join("");
|
.join("");
|
||||||
const listItem = `
|
const listItem = `
|
||||||
<li class="list-group-item" data-part-number="${partNumber}">
|
<li class="list-group-item" data-part-number="${partNumber}">
|
||||||
<span class="part-info" style="cursor: pointer;">${partNumber} - ${partDescription}</span>
|
<span class="part-info" style="cursor: pointer;">${partNumber} - ${partDescription}</span>
|
||||||
<div class="color-picker-container" style="display: inline-block; position: relative; overflow: visible; z-index: 2000;">
|
<div class="color-picker-container" style="display:inline-block; position: relative; overflow: visible; z-index: 2000; margin-left:5px;">
|
||||||
<div class="color-option selected-color" style="background-color: ${partColor}; width: 20px; height: 20px; display: inline-block; margin-left: 5px; cursor: pointer; pointer-events: auto;"></div>
|
<div class="color-option selected-color" style="background-color: ${partColor}; width: 20px; height: 20px; display: inline-block; cursor: pointer; pointer-events: auto;"></div>
|
||||||
<div class="color-picker" style="display: none; position: absolute; right: 0; z-index: 2000; background: #fff; border: 1px solid #ccc; padding: 5px;">${colorOptions}</div>
|
<div class="color-picker" style="display: none; position: absolute; right: 0; z-index: 2000; background: #fff; border: 1px solid #ccc; padding: 5px;">${colorOptions}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display:inline-flex; align-items:center; gap:4px; margin-left:5px;">
|
||||||
|
<input type="range" class="marker-size-slider"
|
||||||
|
min="12" max="48" step="2"
|
||||||
|
value="${partSizes[partNumber] || globalMarkerSize}"
|
||||||
|
style="width:70px;">
|
||||||
|
<span class="marker-size-value" style="font-size:0.8rem;">${partSizes[partNumber] || globalMarkerSize}px</span>
|
||||||
|
</div>
|
||||||
</li>`;
|
</li>`;
|
||||||
partsListElement.append(listItem);
|
partsListElement.append(listItem);
|
||||||
}
|
}
|
||||||
@@ -663,8 +669,21 @@ $(document).ready(function () {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const $listItem = $(this);
|
const $listItem = $(this);
|
||||||
selectedPartNumber = $listItem.data("part-number");
|
const partNumber = $listItem.data("part-number");
|
||||||
|
|
||||||
|
if (
|
||||||
|
selectedPartNumber == partNumber &&
|
||||||
|
$listItem.hasClass("active")
|
||||||
|
) {
|
||||||
|
selectedPartNumber = null;
|
||||||
|
$listItem.removeClass("active");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedPartNumber = partNumber;
|
||||||
$listItem.addClass("active").siblings().removeClass("active");
|
$listItem.addClass("active").siblings().removeClass("active");
|
||||||
console.log(
|
console.log(
|
||||||
"Parte selezionata tramite riga:",
|
"Parte selezionata tramite riga:",
|
||||||
@@ -687,30 +706,88 @@ $(document).ready(function () {
|
|||||||
$picker.toggle();
|
$picker.toggle();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// === Gestione cambio colore ===
|
||||||
partsListElement
|
partsListElement
|
||||||
.off("click.colorOption")
|
.off("click.colorOption")
|
||||||
.on("click.colorOption", ".color-option", function (e) {
|
.on("click.colorOption", ".color-option", function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const $this = $(this);
|
const $this = $(this);
|
||||||
const color = $this.data("color");
|
const color = $this.data("color");
|
||||||
const $listItem = $this.closest("li");
|
const $listItem = $this.closest("li");
|
||||||
const partNumber = $listItem.data("part-number");
|
const partNumber = $listItem.data("part-number");
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"Cliccato .color-option, colore:",
|
"Cliccato .color-option, colore:",
|
||||||
color,
|
color,
|
||||||
"per parte:",
|
"per parte:",
|
||||||
partNumber,
|
partNumber,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Salva il nuovo colore
|
||||||
partColors[partNumber] = color;
|
partColors[partNumber] = color;
|
||||||
|
|
||||||
|
// Aggiorna il colore visivo nel selettore
|
||||||
$listItem
|
$listItem
|
||||||
.find(".selected-color")
|
.find(".selected-color")
|
||||||
.css("background-color", color);
|
.css("background-color", color);
|
||||||
|
|
||||||
|
let currentPhoto = $("#samplePhotoAnnotations").attr("src");
|
||||||
|
let annotations = photoAnnotations[currentPhoto];
|
||||||
|
|
||||||
|
if (annotations) {
|
||||||
|
annotations.markers.forEach(function (m) {
|
||||||
|
if (m.partNumber == partNumber) {
|
||||||
|
m.color = color;
|
||||||
|
let group = markerObjects[m.id];
|
||||||
|
|
||||||
|
if (group) {
|
||||||
|
let circle = group.item(0);
|
||||||
|
|
||||||
|
circle.set("fill", color);
|
||||||
|
circle.set("stroke", color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fabricCanvas.renderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chiudi la palette e aggiorna canvas
|
||||||
$this.closest(".color-picker").hide();
|
$this.closest(".color-picker").hide();
|
||||||
updateMarkers();
|
updateMarkers();
|
||||||
markUnsaved();
|
markUnsaved();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// === Slider locale per dimensione marker ===
|
||||||
|
partsListElement
|
||||||
|
.off("input.localMarkerSize")
|
||||||
|
.on("input.localMarkerSize", ".marker-size-slider", function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Riferimenti alla parte e valore scelto
|
||||||
|
const $slider = $(this);
|
||||||
|
const partNumber = $slider.closest("li").data("part-number");
|
||||||
|
const newSize = parseInt($slider.val());
|
||||||
|
|
||||||
|
// Aggiorna il valore visivo accanto allo slider
|
||||||
|
$slider.siblings(".marker-size-value").text(newSize + "px");
|
||||||
|
|
||||||
|
// Memorizza la nuova dimensione per quella parte
|
||||||
|
partSizes[partNumber] = newSize;
|
||||||
|
|
||||||
|
// Aggiorna i marker sul canvas
|
||||||
|
updateMarkers();
|
||||||
|
|
||||||
|
// Segnala modifiche non salvate
|
||||||
|
markUnsaved();
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Dimensione marker aggiornata per parte ${partNumber}: ${newSize}px`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$(document)
|
$(document)
|
||||||
.off("click.colorPicker")
|
.off("click.colorPicker")
|
||||||
.on("click.colorPicker", function (e) {
|
.on("click.colorPicker", function (e) {
|
||||||
@@ -721,6 +798,48 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enableDragDropPartsList() {
|
||||||
|
const list = $("#partsListAnnotations");
|
||||||
|
if (!list.length || typeof $.ui === "undefined" || !$.ui.sortable) {
|
||||||
|
console.warn("jQuery UI o .sortable non disponibile. Ritento...");
|
||||||
|
setTimeout(enableDragDropPartsList, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.hasClass("ui-sortable")) {
|
||||||
|
list.sortable("destroy"); // evita duplicati
|
||||||
|
}
|
||||||
|
|
||||||
|
list.sortable({
|
||||||
|
items: "li.list-group-item",
|
||||||
|
placeholder: "list-group-item placeholder",
|
||||||
|
axis: "y",
|
||||||
|
containment: "parent",
|
||||||
|
tolerance: "pointer",
|
||||||
|
start: function (e, ui) {
|
||||||
|
ui.item.addClass("dragging");
|
||||||
|
},
|
||||||
|
stop: function (e, ui) {
|
||||||
|
ui.item.removeClass("dragging");
|
||||||
|
const newOrder = [];
|
||||||
|
list.find("li").each(function () {
|
||||||
|
const partNumber = $(this).data("part-number");
|
||||||
|
const part = partsListData.find(
|
||||||
|
(p) => p.part_number == partNumber,
|
||||||
|
);
|
||||||
|
if (part) newOrder.push(part);
|
||||||
|
});
|
||||||
|
partsListData = newOrder;
|
||||||
|
console.log(
|
||||||
|
"Ordine parti aggiornato:",
|
||||||
|
partsListData.map((p) => p.part_number),
|
||||||
|
);
|
||||||
|
markUnsaved();
|
||||||
|
updateMarkers();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Delegazione evento per il checkbox
|
// Delegazione evento per il checkbox
|
||||||
$(document)
|
$(document)
|
||||||
.off("change.showMix", "#showMixPartsAnnotations")
|
.off("change.showMix", "#showMixPartsAnnotations")
|
||||||
@@ -753,6 +872,7 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
updateMarkers();
|
updateMarkers();
|
||||||
|
setTimeout(enableDragDropPartsList, 50);
|
||||||
if (
|
if (
|
||||||
photoAnnotations[$("#samplePhotoAnnotations").attr("src")]
|
photoAnnotations[$("#samplePhotoAnnotations").attr("src")]
|
||||||
?.hasDescriptions
|
?.hasDescriptions
|
||||||
@@ -860,9 +980,9 @@ $(document).ready(function () {
|
|||||||
"updateMarkers chiamato, markerObjects:",
|
"updateMarkers chiamato, markerObjects:",
|
||||||
Object.keys(markerObjects),
|
Object.keys(markerObjects),
|
||||||
);
|
);
|
||||||
for (let partNumber in markerObjects) {
|
for (let markerId in markerObjects) {
|
||||||
fabricCanvas.remove(markerObjects[partNumber]);
|
fabricCanvas.remove(markerObjects[markerId]);
|
||||||
delete markerObjects[partNumber];
|
delete markerObjects[markerId];
|
||||||
}
|
}
|
||||||
markerObjects = {};
|
markerObjects = {};
|
||||||
|
|
||||||
@@ -892,8 +1012,10 @@ $(document).ready(function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const radius = 12;
|
const size = partSizes[marker.partNumber] || globalMarkerSize;
|
||||||
const fontSize = 16;
|
const radius = size / 2;
|
||||||
|
const fontSize = Math.max(10, Math.round(size * 0.65));
|
||||||
|
|
||||||
const markerColor =
|
const markerColor =
|
||||||
marker.color || partColors[marker.partNumber] || "#ff0000";
|
marker.color || partColors[marker.partNumber] || "#ff0000";
|
||||||
|
|
||||||
@@ -941,6 +1063,9 @@ $(document).ready(function () {
|
|||||||
lockRotation: true,
|
lockRotation: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.markerId = marker.id;
|
||||||
|
group.partNumber = marker.partNumber;
|
||||||
|
|
||||||
group.on("moving", function () {
|
group.on("moving", function () {
|
||||||
marker.x = this.left / photoData.scale;
|
marker.x = this.left / photoData.scale;
|
||||||
marker.y = this.top / photoData.scale;
|
marker.y = this.top / photoData.scale;
|
||||||
@@ -953,7 +1078,7 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
fabricCanvas.add(group);
|
fabricCanvas.add(group);
|
||||||
markerObjects[marker.partNumber] = group;
|
markerObjects[marker.id] = group;
|
||||||
});
|
});
|
||||||
|
|
||||||
fabricCanvas.renderAll();
|
fabricCanvas.renderAll();
|
||||||
@@ -1013,7 +1138,7 @@ $(document).ready(function () {
|
|||||||
scaleY: 1,
|
scaleY: 1,
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
fontFamily: "Arial",
|
fontFamily: "Arial",
|
||||||
fontSize: 24,
|
fontSize: Math.max(16, Math.round(globalMarkerSize * 0.8)),
|
||||||
fill: "#000000",
|
fill: "#000000",
|
||||||
padding: 10,
|
padding: 10,
|
||||||
editable: false,
|
editable: false,
|
||||||
@@ -1107,9 +1232,9 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let partNumber in markerObjects) {
|
for (let markerId in markerObjects) {
|
||||||
fabricCanvas.remove(markerObjects[partNumber]);
|
fabricCanvas.remove(markerObjects[markerId]);
|
||||||
delete markerObjects[partNumber];
|
delete markerObjects[markerId];
|
||||||
}
|
}
|
||||||
markerObjects = {};
|
markerObjects = {};
|
||||||
|
|
||||||
@@ -1144,9 +1269,9 @@ $(document).ready(function () {
|
|||||||
photoAnnotations[currentPhoto].markers.length > 0
|
photoAnnotations[currentPhoto].markers.length > 0
|
||||||
) {
|
) {
|
||||||
const lastMarker = photoAnnotations[currentPhoto].markers.pop();
|
const lastMarker = photoAnnotations[currentPhoto].markers.pop();
|
||||||
if (markerObjects[lastMarker.partNumber]) {
|
if (markerObjects[lastMarker.id]) {
|
||||||
fabricCanvas.remove(markerObjects[lastMarker.partNumber]);
|
fabricCanvas.remove(markerObjects[lastMarker.id]);
|
||||||
delete markerObjects[lastMarker.partNumber];
|
delete markerObjects[lastMarker.id];
|
||||||
fabricCanvas.renderAll();
|
fabricCanvas.renderAll();
|
||||||
}
|
}
|
||||||
console.log("Ultimo marker rimosso:", lastMarker);
|
console.log("Ultimo marker rimosso:", lastMarker);
|
||||||
|
|||||||
@@ -24,7 +24,17 @@ class VisualLimsApiClient
|
|||||||
public static function getInstance()
|
public static function getInstance()
|
||||||
{
|
{
|
||||||
if (self::$instance === null) {
|
if (self::$instance === null) {
|
||||||
self::$instance = new VisualLimsApiClient();
|
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3));
|
||||||
|
$dotenv->load();
|
||||||
|
|
||||||
|
$simulate = ($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true';
|
||||||
|
|
||||||
|
if ($simulate) {
|
||||||
|
require_once __DIR__ . '/VisualLimsApiClientMock.class.php';
|
||||||
|
self::$instance = new VisualLimsApiClientMock();
|
||||||
|
} else {
|
||||||
|
self::$instance = new VisualLimsApiClient();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
@@ -193,6 +203,54 @@ class VisualLimsApiClient
|
|||||||
return json_decode($response, true);
|
return json_decode($response, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST a file as multipart/form-data (used for photo/attachment uploads).
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* @param array $extraFields Additional form fields to include
|
||||||
|
* @return array|null Decoded JSON response
|
||||||
|
*/
|
||||||
|
public function postMultipart($endpoint, $filePath, $fileName, array $extraFields = [])
|
||||||
|
{
|
||||||
|
$token = $this->getToken();
|
||||||
|
$url = "{$this->baseUrl}/api/odata/{$endpoint}";
|
||||||
|
|
||||||
|
$cfile = new CURLFile($filePath, mime_content_type($filePath) ?: 'application/octet-stream', $fileName);
|
||||||
|
|
||||||
|
$payload = array_merge($extraFields, [
|
||||||
|
'file' => $cfile,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
"Authorization: Bearer {$token}",
|
||||||
|
"Accept: application/json",
|
||||||
|
// Content-Type is set automatically to multipart/form-data by cURL
|
||||||
|
]);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false) {
|
||||||
|
throw new Exception("Errore nella richiesta POST multipart: {$curl_error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($http_code < 200 || $http_code >= 300) {
|
||||||
|
throw new Exception("POST multipart fallito: HTTP {$http_code}, Risposta: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_decode($response, true);
|
||||||
|
}
|
||||||
|
|
||||||
public function getBaseUrl()
|
public function getBaseUrl()
|
||||||
{
|
{
|
||||||
return $this->baseUrl;
|
return $this->baseUrl;
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock implementation of VisualLimsApiClient.
|
||||||
|
* Activated when SIMULATE_EXPORT_LIMS=true in .env.
|
||||||
|
* All HTTP calls are skipped; fake but structurally valid data is returned.
|
||||||
|
* Every simulated call is logged via error_log() with a [SIMULATE] prefix.
|
||||||
|
*/
|
||||||
|
class VisualLimsApiClientMock
|
||||||
|
{
|
||||||
|
private int $fakeCommessaId;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Stable fake ID for the lifetime of a single request
|
||||||
|
$this->fakeCommessaId = mt_rand(90001, 99999);
|
||||||
|
error_log("[SIMULATE] VisualLimsApiClientMock initialised (fakeCommessaId={$this->fakeCommessaId})");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $endpoint): array
|
||||||
|
{
|
||||||
|
error_log("[SIMULATE] GET {$endpoint}");
|
||||||
|
|
||||||
|
// --- Fixed-field dropdown lists ---
|
||||||
|
|
||||||
|
if (str_starts_with($endpoint, 'MoltiplicatorePrezzi')) {
|
||||||
|
return ['value' => [
|
||||||
|
['IdMoltiplicatorePrezzo' => 1, 'Codice' => 'MP-01', 'Descrizione' => 'Standard (1x)'],
|
||||||
|
['IdMoltiplicatorePrezzo' => 2, 'Codice' => 'MP-02', 'Descrizione' => 'Urgente (1.5x)'],
|
||||||
|
['IdMoltiplicatorePrezzo' => 3, 'Codice' => 'MP-03', 'Descrizione' => 'Extra Urgente (2x)'],
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($endpoint, 'AnagraficaCertestObject')) {
|
||||||
|
return ['value' => [
|
||||||
|
['IdAnagrafica' => 1, 'Codice' => 'OBJ-01', 'NomeAnagrafica' => 'Articolo Tessile'],
|
||||||
|
['IdAnagrafica' => 2, 'Codice' => 'OBJ-02', 'NomeAnagrafica' => 'Componente Meccanico'],
|
||||||
|
['IdAnagrafica' => 3, 'Codice' => 'OBJ-03', 'NomeAnagrafica' => 'Materiale Plastico'],
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($endpoint, 'AnagraficaCertestService')) {
|
||||||
|
return ['value' => [
|
||||||
|
['IdAnagrafica' => 1, 'Codice' => 'SRV-01', 'NomeAnagrafica' => 'Analisi Chimica'],
|
||||||
|
['IdAnagrafica' => 2, 'Codice' => 'SRV-02', 'NomeAnagrafica' => 'Test Meccanico'],
|
||||||
|
['IdAnagrafica' => 3, 'Codice' => 'SRV-03', 'NomeAnagrafica' => 'Prova Ambientale'],
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cliente? list — get_clienti.php exits early in simulate mode, but guard here too
|
||||||
|
if (str_starts_with($endpoint, 'Cliente?')) {
|
||||||
|
return ['value' => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cliente(N)?$expand=Responsabili
|
||||||
|
if (str_starts_with($endpoint, 'Cliente(')) {
|
||||||
|
preg_match('/Cliente\((\d+)\)/', $endpoint, $m);
|
||||||
|
$clienteId = isset($m[1]) ? (int) $m[1] : 0;
|
||||||
|
return [
|
||||||
|
'IdCliente' => $clienteId,
|
||||||
|
'Responsabili' => [
|
||||||
|
['IdClienteResponsabile' => 1, 'Nominativo' => 'Marco Bianchi'],
|
||||||
|
['IdClienteResponsabile' => 2, 'Nominativo' => 'Giulia Ferrari'],
|
||||||
|
['IdClienteResponsabile' => 3, 'Nominativo' => 'Andrea Russo'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- CustomField dropdown values (get_customfield_values.php) ---
|
||||||
|
|
||||||
|
if (str_starts_with($endpoint, 'CustomField(')) {
|
||||||
|
preg_match('/CustomField\((\d+)\)/', $endpoint, $m);
|
||||||
|
$fieldId = isset($m[1]) ? (int) $m[1] : 0;
|
||||||
|
return [
|
||||||
|
'CustomFieldsValues' => [
|
||||||
|
['IdCustomFieldsValue' => $fieldId * 10 + 1, 'Valore' => 'Opzione A'],
|
||||||
|
['IdCustomFieldsValue' => $fieldId * 10 + 2, 'Valore' => 'Opzione B'],
|
||||||
|
['IdCustomFieldsValue' => $fieldId * 10 + 3, 'Valore' => 'Opzione C'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- CommessaWeb OData calls (STEP 7 GET + STEP 10 verification) ---
|
||||||
|
|
||||||
|
preg_match('/\((\d+)\)/', $endpoint, $m);
|
||||||
|
$id = isset($m[1]) ? (int) $m[1] : $this->fakeCommessaId;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'IdCommessa' => $id,
|
||||||
|
'CodiceCommessa' => "SIM-{$id}",
|
||||||
|
'CommesseCustomFields' => [], // Empty → PATCH step is skipped correctly
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post(string $endpoint, array $payload): array
|
||||||
|
{
|
||||||
|
error_log("[SIMULATE] POST {$endpoint} payload=" . json_encode($payload));
|
||||||
|
|
||||||
|
// CommessaWeb creation
|
||||||
|
if ($endpoint === 'CommessaWeb') {
|
||||||
|
return [
|
||||||
|
'IdCommessa' => $this->fakeCommessaId,
|
||||||
|
'CodiceCommessa' => "SIM-{$this->fakeCommessaId}",
|
||||||
|
'Richiedente' => $payload['Richiedente'] ?? '',
|
||||||
|
'Descrizione' => $payload['Descrizione'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Campione creation
|
||||||
|
if ($endpoint === 'Campione') {
|
||||||
|
return [
|
||||||
|
'IdCampione' => mt_rand(10001, 19999),
|
||||||
|
'Commessa' => $payload['Commessa'] ?? null,
|
||||||
|
'Matrice' => $payload['Matrice'] ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// InviaCommessa / ImportaCommessa (currently commented out upstream)
|
||||||
|
return ['simulated' => true, 'endpoint' => $endpoint];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function patch(string $endpoint, array $payload): array
|
||||||
|
{
|
||||||
|
error_log("[SIMULATE] PATCH {$endpoint} payload=" . json_encode($payload));
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postMultipart(string $endpoint, string $filePath, string $fileName, array $extraFields = []): array
|
||||||
|
{
|
||||||
|
error_log("[SIMULATE] POST multipart {$endpoint} file={$fileName}");
|
||||||
|
|
||||||
|
return ['simulated' => true, 'file' => $fileName];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
require_once(__DIR__ . '/include/headscript.php');
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
$templateId = (int)($input['template_id'] ?? 0);
|
||||||
|
|
||||||
|
if ($templateId <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid template_id']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If already exists, do nothing
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM template_fixed_mapping WHERE template_id = ?");
|
||||||
|
$stmt->execute([$templateId]);
|
||||||
|
if ((int)$stmt->fetchColumn() > 0) {
|
||||||
|
echo json_encode(['success' => true, 'created' => 0, 'message' => 'Fixed fields already exist']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXED FIELDS STANDARD (no UI selection)
|
||||||
|
* is_manual always 1
|
||||||
|
* is_visible_import default 1
|
||||||
|
*/
|
||||||
|
$fixedFields = [
|
||||||
|
// fixed_field_key, data_type
|
||||||
|
['ClienteResponsabile', 'INT'],
|
||||||
|
['ClienteFornitore', 'INT'],
|
||||||
|
['ClienteAnalisi', 'INT'],
|
||||||
|
['MoltiplicatorePrezzo', 'INT'],
|
||||||
|
['AnagraficaCertestObject', 'INT'],
|
||||||
|
['AnagraficaCertestService', 'INT'],
|
||||||
|
['ConsegnaRichiesta', 'DATE'],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
$ins = $pdo->prepare("
|
||||||
|
INSERT INTO template_fixed_mapping
|
||||||
|
(template_id, fixed_field_key, is_manual, data_type, is_required, default_value, is_visible_import)
|
||||||
|
VALUES
|
||||||
|
(:template_id, :fixed_field_key, 1, :data_type, 1, NULL, 1)
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($fixedFields as $f) {
|
||||||
|
$ins->execute([
|
||||||
|
':template_id' => $templateId,
|
||||||
|
':fixed_field_key' => $f[0],
|
||||||
|
':data_type' => $f[1],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
// Return rows (for client render)
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT id, template_id, fixed_field_key, is_manual, data_type, is_required, default_value, is_visible_import
|
||||||
|
FROM template_fixed_mapping
|
||||||
|
WHERE template_id = ?
|
||||||
|
ORDER BY id ASC
|
||||||
|
");
|
||||||
|
|
||||||
|
$stmt->execute([$templateId]);
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'created' => count($rows), 'rows' => $rows]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,290 @@
|
|||||||
|
<?php
|
||||||
|
require_once "class/VisualLimsApiClient.class.php";
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
// Force HTML response
|
||||||
|
header('Content-Type: text/html; charset=UTF-8');
|
||||||
|
|
||||||
|
// Initialize variables
|
||||||
|
$error = null;
|
||||||
|
$result = null;
|
||||||
|
$entityType = $_GET['entity_type'] ?? 'CommessaWeb';
|
||||||
|
$entityId = isset($_GET['entity_id']) ? (int)$_GET['entity_id'] : 0;
|
||||||
|
$customExpand = trim($_GET['expand'] ?? '');
|
||||||
|
$rawEndpoint = null;
|
||||||
|
|
||||||
|
function h($value)
|
||||||
|
{
|
||||||
|
return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderArrayAsTable(array $items)
|
||||||
|
{
|
||||||
|
if (empty($items)) {
|
||||||
|
echo '<div class="alert alert-secondary">No records found</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$firstRow = reset($items);
|
||||||
|
if (!is_array($firstRow)) {
|
||||||
|
echo '<pre class="bg-light p-3 border rounded">' . h(json_encode($items, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) . '</pre>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = [];
|
||||||
|
foreach ($items as $row) {
|
||||||
|
if (is_array($row)) {
|
||||||
|
$headers = array_unique(array_merge($headers, array_keys($row)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '<div class="table-responsive">';
|
||||||
|
echo '<table class="table table-striped table-bordered table-sm align-middle">';
|
||||||
|
echo '<thead class="table-dark"><tr>';
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
echo '<th>' . h($header) . '</th>';
|
||||||
|
}
|
||||||
|
echo '</tr></thead><tbody>';
|
||||||
|
|
||||||
|
foreach ($items as $row) {
|
||||||
|
echo '<tr>';
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
$value = $row[$header] ?? '';
|
||||||
|
if (is_array($value) || is_object($value)) {
|
||||||
|
$value = json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
echo '<td><pre style="white-space:pre-wrap; margin:0;">' . h($value) . '</pre></td>';
|
||||||
|
} else {
|
||||||
|
echo '<td>' . h($value) . '</td>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</tbody></table>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($entityId > 0) {
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Default expands for better debugging
|
||||||
|
if ($customExpand !== '') {
|
||||||
|
$expand = $customExpand;
|
||||||
|
} else {
|
||||||
|
if ($entityType === 'CommessaWeb') {
|
||||||
|
$expand = implode(',', [
|
||||||
|
'CommesseCustomFields($expand=CustomField)',
|
||||||
|
'Campioni'
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$expand = implode(',', [
|
||||||
|
'CommesseCustomFields($expand=CustomField)',
|
||||||
|
'Campioni'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rawEndpoint = $entityType . '(' . $entityId . ')?$expand=' . $expand;
|
||||||
|
$result = $api->get($rawEndpoint);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = $e->getMessage();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Debug Commessa API</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: #f5f7fb;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-box {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #eef3ff;
|
||||||
|
color: #2446a8;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-box {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #e4e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-box strong {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: #1f2937;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container py-4">
|
||||||
|
<div class="debug-card">
|
||||||
|
<h2 class="mb-3">Commessa / CommessaWeb API Inspector</h2>
|
||||||
|
|
||||||
|
<form method="GET" class="row g-3">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label">Entity Type</label>
|
||||||
|
<select name="entity_type" class="form-select">
|
||||||
|
<option value="CommessaWeb" <?= $entityType === 'CommessaWeb' ? 'selected' : '' ?>>CommessaWeb</option>
|
||||||
|
<option value="Commessa" <?= $entityType === 'Commessa' ? 'selected' : '' ?>>Commessa</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label">Entity ID</label>
|
||||||
|
<input type="number" name="entity_id" class="form-control" value="<?= h($entityId) ?>" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-5">
|
||||||
|
<label class="form-label">Expand</label>
|
||||||
|
<input type="text" name="expand" class="form-control" value="<?= h($customExpand) ?>" placeholder="CommesseCustomFields($expand=CustomField),Campioni">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-2 d-flex align-items-end">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">Load Data</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($rawEndpoint): ?>
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="section-title">Requested Endpoint</div>
|
||||||
|
<pre><?= h($rawEndpoint) ?></pre>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="alert alert-danger mb-0">
|
||||||
|
<strong>API Error:</strong><br>
|
||||||
|
<?= h($error) ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($result && is_array($result)): ?>
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="section-title">Main Information</div>
|
||||||
|
<div class="mini-grid">
|
||||||
|
<div class="mini-box">
|
||||||
|
<strong>ID</strong>
|
||||||
|
<?= h($result['IdCommessa'] ?? $result['IdCommessaWeb'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
<div class="mini-box">
|
||||||
|
<strong>Code</strong>
|
||||||
|
<?= h($result['CodiceCommessa'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
<div class="mini-box">
|
||||||
|
<strong>Cliente</strong>
|
||||||
|
<?= h($result['Cliente'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
<div class="mini-box">
|
||||||
|
<strong>SchemaCustomField</strong>
|
||||||
|
<?= h($result['SchemaCustomField'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
<div class="mini-box">
|
||||||
|
<strong>Richiedente</strong>
|
||||||
|
<?= h($result['Richiedente'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
<div class="mini-box">
|
||||||
|
<strong>Descrizione</strong>
|
||||||
|
<?= h($result['Descrizione'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="section-title">Direct Properties</div>
|
||||||
|
<pre><?= h(json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) ?></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!empty($result['CommesseCustomFields']) && is_array($result['CommesseCustomFields'])): ?>
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="section-title">CommesseCustomFields</div>
|
||||||
|
<?php
|
||||||
|
$fieldsRows = [];
|
||||||
|
foreach ($result['CommesseCustomFields'] as $field) {
|
||||||
|
$fieldsRows[] = [
|
||||||
|
'IdCommesseCustomFields' => $field['IdCommesseCustomFields'] ?? '',
|
||||||
|
'Valore' => $field['Valore'] ?? '',
|
||||||
|
'CustomFieldId' => $field['CustomField']['IdCustomField'] ?? '',
|
||||||
|
'Label' => $field['CustomField']['Descrizione'] ?? ($field['CustomField']['Name'] ?? ''),
|
||||||
|
'Tipo' => $field['CustomField']['Tipo'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
renderArrayAsTable($fieldsRows);
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($result['Campioni']) && is_array($result['Campioni'])): ?>
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="section-title">Campioni</div>
|
||||||
|
<?php renderArrayAsTable($result['Campioni']); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="section-title">Raw JSON</div>
|
||||||
|
<pre><?= h(json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) ?></pre>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($entityId > 0 && !$error): ?>
|
||||||
|
<div class="debug-card">
|
||||||
|
<div class="alert alert-warning mb-0">No data returned from API</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<!-- Example of use
|
||||||
|
debug_commessa_api.php?entity_type=CommessaWeb&entity_id=564779
|
||||||
|
debug_commessa_api.php?entity_type=Commessa&entity_id=12345
|
||||||
|
debug_commessa_api.php?entity_type=CommessaWeb&entity_id=564779&expand=CommesseCustomFields($expand=CustomField),Campioni
|
||||||
|
-->
|
||||||
@@ -12,3 +12,319 @@
|
|||||||
2025-08-26 16:49:24 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
2025-08-26 16:49:24 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
2025-08-26 16:50:23 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
2025-08-26 16:50:23 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
2025-09-08 08:39:17 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
2025-09-08 08:39:17 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
2026-01-27 15:33:53 - Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-27 15:34:06 - Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-27 15:34:10 - Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-27 15:35:13 - Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:33:38 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:33:39 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-01-29 14:34:04 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:37:29 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:41:55 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:42:03 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:42:52 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-29 14:43:00 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
|
||||||
|
2026-01-30 10:50:43 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-01-30 10:50:43 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-01-30 11:09:22 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-02-19 10:00:13 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-02-19 10:00:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-02-19 10:00:44 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-02-23 10:44:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:42 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:43 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:43 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:43 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:44:53 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:48:26 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:48:26 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:48:27 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:48:27 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:48:27 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:49:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:49:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:49:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:49:05 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 10:49:05 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 14:26:52 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 14:26:59 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 15:54:16 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 16:22:45 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-23 16:32:17 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<HTML><HEAD><TITLE>Not Found</TITLE>
|
||||||
|
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
|
||||||
|
<BODY><h2>Not Found</h2>
|
||||||
|
<hr><p>HTTP Error 404. The requested resource is not found.</p>
|
||||||
|
</BODY></HTML>
|
||||||
|
|
||||||
|
2026-02-25 15:23:12 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-02-26 15:01:32 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-02-28 21:01:27 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-03-01 19:11:58 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-03-18 15:51:45 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-03-19 09:50:34 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
|
||||||
|
2026-03-25 14:13:34 - Autenticazione fallita: HTTP 503, Errore cURL: , Risposta: The service is unavailable.
|
||||||
|
2026-03-25 14:13:34 - Autenticazione fallita: HTTP 503, Errore cURL: , Risposta: The service is unavailable.
|
||||||
|
2026-03-26 10:57:18 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:21 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:21 [AnagraficaCertestService] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:21 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:36 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:36 [AnagraficaCertestService] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:36 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:41 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:57:56 [AnagraficaCertestObject] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
2026-03-26 10:58:11 [AnagraficaCertestService] Autenticazione fallita: HTTP 500, Errore cURL: , Risposta: {"title":"Internal Server Error","status":500,"detail":"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.","instance":"POST /api/authentication/authenticate","errorCode":"63ab532c6"}
|
||||||
|
|||||||
+774
-213
File diff suppressed because it is too large
Load Diff
@@ -13,9 +13,31 @@ if (!is_dir($logDir)) {
|
|||||||
mkdir($logDir, 0755, true);
|
mkdir($logDir, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$uploadDir = realpath(__DIR__ . '/../photostrf') . '/';
|
||||||
|
|
||||||
// 🔹 Base URL API
|
// 🔹 Base URL API
|
||||||
$apiBaseUrl = 'https://93.43.5.102/limsapi/api/odata/';
|
$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
|
// 🔹 Funzione per validare e convertire date
|
||||||
function validateDate($value)
|
function validateDate($value)
|
||||||
{
|
{
|
||||||
@@ -27,15 +49,38 @@ function validateDate($value)
|
|||||||
return null; // Imposta null se non è una data valida
|
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 {
|
try {
|
||||||
$iddatadb = $_POST['iddatadb'] ?? null;
|
$iddatadb = $_POST['iddatadb'] ?? null;
|
||||||
if (!$iddatadb) {
|
if (!$iddatadb) {
|
||||||
throw new Exception("Missing 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
|
// 🔹 STEP 1+2: Fetch Cliente ID from datadb and Schema ID from excel_templates
|
||||||
|
// Also fetch fixed fields stored in datadb
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT d.idclient AS clienteId, et.idschema AS schemaId
|
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.clienteAnalisi,
|
||||||
|
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
|
||||||
@@ -51,15 +96,58 @@ try {
|
|||||||
$clienteId = (int) $result['clienteId'];
|
$clienteId = (int) $result['clienteId'];
|
||||||
$schemaId = (int) $result['schemaId'];
|
$schemaId = (int) $result['schemaId'];
|
||||||
|
|
||||||
// 🔹 STEP 3: Fetch Parts (including idmatrice)
|
// 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("
|
$stmt = $pdo->prepare("
|
||||||
SELECT part_number, part_description, material, color, mix, idmatrice
|
SELECT id AS part_id, part_number, part_description, material, color, mix, idmatrice, dateexpiry
|
||||||
FROM identification_parts
|
FROM identification_parts
|
||||||
WHERE iddatadb = :iddatadb
|
WHERE iddatadb = :iddatadb
|
||||||
|
ORDER BY CAST(part_number AS UNSIGNED) ASC, part_number ASC
|
||||||
");
|
");
|
||||||
$stmt->execute(['iddatadb' => $iddatadb]);
|
$stmt->execute(['iddatadb' => $iddatadb]);
|
||||||
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$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
|
// 🔹 STEP 4: Fetch Field Values with Labels
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT
|
SELECT
|
||||||
@@ -93,12 +181,21 @@ try {
|
|||||||
// 🔹 Initialize API client
|
// 🔹 Initialize API client
|
||||||
$api = VisualLimsApiClient::getInstance();
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
// 🔹 STEP 5: Create CommessaWeb (NOT WebOrder)
|
// 🔹 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 = [
|
$commessaWebPayload = [
|
||||||
"Cliente" => $clienteId,
|
"Cliente" => $clienteId,
|
||||||
"SchemaCustomField" => $schemaId,
|
"SchemaCustomField" => $schemaId,
|
||||||
"Richiedente" => "Test Web Import",
|
"Richiedente" => "From TRFSmart Application", // TODO: replace with real value
|
||||||
"Descrizione" => "TEST CommessaWeb",
|
"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
|
// Costruisci log curl-like per STEP 5
|
||||||
@@ -114,7 +211,7 @@ try {
|
|||||||
|
|
||||||
// Salva log
|
// Salva log
|
||||||
$logFileStep5 = $logDir . "commessa_create_step5_" . $iddatadb . "_" . time() . ".txt";
|
$logFileStep5 = $logDir . "commessa_create_step5_" . $iddatadb . "_" . time() . ".txt";
|
||||||
file_put_contents($logFileStep5, $logContentStep5);
|
$writeLog($logFileStep5, $logContentStep5, "STEP 5 - Create CommessaWeb (iddatadb={$iddatadb})");
|
||||||
|
|
||||||
$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
|
||||||
@@ -131,11 +228,13 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$campionePayload = [
|
$campionePayload = [
|
||||||
"Commessa" => $commessaId,
|
"Commessa" => $commessaId,
|
||||||
"Matrice" => $matriceId,
|
"Matrice" => $matriceId,
|
||||||
"SottoMatrice" => null,
|
"SottoMatrice" => null,
|
||||||
"SchemaCustomField" => $schemaId,
|
"SchemaCustomField" => $schemaId,
|
||||||
"NoteWeb" => $part["part_description"] ?? ""
|
// "Riferimento" => $part["part_description"] ?? "",
|
||||||
|
"NoteWeb" => $part["part_description"] ?? "",
|
||||||
|
"ConsegnaRichiesta" => !empty($part["dateexpiry"]) ? $part["dateexpiry"] : $consegnaRichiesta,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Costruisci curl-like per questo campione
|
// Costruisci curl-like per questo campione
|
||||||
@@ -160,20 +259,191 @@ try {
|
|||||||
|
|
||||||
// Salva log per STEP 6
|
// Salva log per STEP 6
|
||||||
$logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt";
|
$logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt";
|
||||||
file_put_contents($logFileStep6, $logContentStep6);
|
$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 Campione .01 (fetched from API)
|
||||||
|
$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)) {
|
||||||
|
// Fetch campioni list from API to find the .01 campione
|
||||||
|
$commessaCampioni = $api->get("CommessaWeb({$commessaId})?\$expand=Campioni");
|
||||||
|
$apiCampioni = $commessaCampioni['Campioni'] ?? [];
|
||||||
|
|
||||||
|
// Sort by CodiceCampione to find .01
|
||||||
|
usort($apiCampioni, fn($a, $b) => strcmp($a['CodiceCampione'] ?? '', $b['CodiceCampione'] ?? ''));
|
||||||
|
|
||||||
|
$mainCampione = $apiCampioni[0] ?? null;
|
||||||
|
$campioneId = (int)($mainCampione['IdCampione'] ?? 0);
|
||||||
|
|
||||||
|
$logContentPhotos .= "API Campioni order:\n";
|
||||||
|
foreach ($apiCampioni as $ac) {
|
||||||
|
$logContentPhotos .= " - {$ac['CodiceCampione']} (IdCampione: {$ac['IdCampione']})\n";
|
||||||
|
}
|
||||||
|
$logContentPhotos .= "Selected .01 campione: IdCampione={$campioneId}\n\n";
|
||||||
|
|
||||||
|
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
|
// 🔹 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" .
|
||||||
"--header 'Authorization: Bearer ••••••'\n\n" .
|
"--header 'Authorization: Bearer ••••••'\n\n" .
|
||||||
"RESPONSE:\n" . json_encode($commessaWithFields, JSON_PRETTY_PRINT);
|
"RESPONSE:\n" . json_encode($commessaWithFields, JSON_PRETTY_PRINT);
|
||||||
$logFileGet = $logDir . "commessa_{$commessaId}_get_step7_" . time() . ".txt";
|
$logFileGet = $logDir . "commessa_{$commessaId}_get_step7_" . time() . ".txt";
|
||||||
file_put_contents($logFileGet, $logContentGet);
|
$writeLog($logFileGet, $logContentGet, "STEP 7 - GET CustomFields (commessa={$commessaId})");
|
||||||
|
|
||||||
// Prepara payload PATCH
|
// Prepara payload PATCH
|
||||||
$commessaCustomFields = [];
|
$commessaCustomFields = [];
|
||||||
@@ -186,7 +456,7 @@ try {
|
|||||||
|
|
||||||
// Valida se il campo è di tipo Data
|
// Valida se il campo è di tipo Data
|
||||||
if ($fieldType === 'Data' && $newValue !== $currentValue) {
|
if ($fieldType === 'Data' && $newValue !== $currentValue) {
|
||||||
$newValue = validateDate($newValue);
|
$newValue = formatDateToExport($newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
$commessaCustomFields[] = [
|
$commessaCustomFields[] = [
|
||||||
@@ -195,6 +465,7 @@ try {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$logFileStep7 = null;
|
||||||
if (!empty($commessaCustomFields)) {
|
if (!empty($commessaCustomFields)) {
|
||||||
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields];
|
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields];
|
||||||
|
|
||||||
@@ -209,7 +480,7 @@ try {
|
|||||||
|
|
||||||
$logContentStep7 .= "\n\nRESPONSE:\n" . json_encode($patchResponse, JSON_PRETTY_PRINT);
|
$logContentStep7 .= "\n\nRESPONSE:\n" . json_encode($patchResponse, JSON_PRETTY_PRINT);
|
||||||
$logFileStep7 = $logDir . "commessa_{$commessaId}_update_step7_" . time() . ".txt";
|
$logFileStep7 = $logDir . "commessa_{$commessaId}_update_step7_" . time() . ".txt";
|
||||||
file_put_contents($logFileStep7, $logContentStep7);
|
$writeLog($logFileStep7, $logContentStep7, "STEP 7 - PATCH CustomFields (commessa={$commessaId})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,18 +497,40 @@ try {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto)
|
// 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto)
|
||||||
/*
|
|
||||||
$sendResult = $api->post("CommessaWeb({$commessaId})/InviaCommessa", []);
|
$sendResult = $api->post("CommessaWeb({$commessaId})/InviaCommessa", []);
|
||||||
|
|
||||||
// Logga il POST
|
// Logga il POST
|
||||||
$logContentStep9 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/InviaCommessa' \\\n" .
|
$logContentStep9 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/InviaCommessa' \\\n" .
|
||||||
"--header 'Content-Type: application/json' \\\n" .
|
"--header 'Content-Type: application/json' \\\n" .
|
||||||
"--header 'Authorization: Bearer ••••••' \\\n" .
|
"--header 'Authorization: Bearer ••••••' \\\n" .
|
||||||
"--data '{}'\n\n" .
|
"--data '{}'\n\n" .
|
||||||
"RESPONSE:\n" . json_encode($sendResult, JSON_PRETTY_PRINT);
|
"RESPONSE:\n" . json_encode($sendResult, JSON_PRETTY_PRINT);
|
||||||
$logFileStep9 = $logDir . "commessa_{$commessaId}_send_step9_" . time() . ".txt";
|
$logFileStep9 = $logDir . "commessa_{$commessaId}_send_step9_" . time() . ".txt";
|
||||||
file_put_contents($logFileStep9, $logContentStep9);
|
$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
|
||||||
|
|
||||||
|
$importUserId = (!empty($lims_global_user_id) && is_numeric($lims_global_user_id))
|
||||||
|
? (int) $lims_global_user_id
|
||||||
|
: 285;
|
||||||
|
|
||||||
|
$importPayload = [
|
||||||
|
"IdUtente" => $importUserId
|
||||||
|
];
|
||||||
|
$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
|
// 🔹 STEP 10: GET di controllo post-PATCH
|
||||||
$expand = "CommesseCustomFields(\$expand=CustomField)";
|
$expand = "CommesseCustomFields(\$expand=CustomField)";
|
||||||
@@ -248,7 +541,7 @@ try {
|
|||||||
"--header 'Authorization: Bearer ••••••'\n\n" .
|
"--header 'Authorization: Bearer ••••••'\n\n" .
|
||||||
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
|
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
|
||||||
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
|
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
|
||||||
file_put_contents($logFileStep10, $logContentStep10);
|
$writeLog($logFileStep10, $logContentStep10, "STEP 10 - GET verify (commessa={$commessaId})");
|
||||||
|
|
||||||
// 🔹 STEP 11: Prepare final response
|
// 🔹 STEP 11: Prepare final response
|
||||||
$finalCommessa = [
|
$finalCommessa = [
|
||||||
@@ -262,17 +555,22 @@ try {
|
|||||||
];
|
];
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
"success" => true,
|
"success" => true,
|
||||||
"commessaWeb" => $finalCommessa,
|
"idcommessaweb" => $commessaId,
|
||||||
|
"commessaweb" => $commessaWebCode,
|
||||||
|
"commessaWeb" => $finalCommessa,
|
||||||
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
|
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
|
||||||
"totalCampioni" => count($campioni),
|
"totalCampioni" => count($campioni),
|
||||||
"totalCustomFields" => count($commessaAfterPatch["CommesseCustomFields"] ?? []),
|
"totalCustomFields" => count($commessaAfterPatch["CommesseCustomFields"] ?? []),
|
||||||
"message" => "Export successful",
|
"totalPhotos" => count($photos),
|
||||||
"logFiles" => [
|
"message" => "Export successful",
|
||||||
"step5_create" => $logFileStep5,
|
"logFiles" => [
|
||||||
"step6_campioni" => $logFileStep6,
|
"step5_create" => $logFileStep5,
|
||||||
"step7_patch" => $logFileStep7,
|
"step5_2_photos" => $logFilePhotos,
|
||||||
"step10_get" => $logFileStep10
|
"step6_campioni" => $logFileStep6,
|
||||||
|
"step7_patch" => $logFileStep7 ?? null,
|
||||||
|
"step9_1_importa" => $logFileStep91,
|
||||||
|
"step10_get" => $logFileStep10
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@@ -282,10 +580,12 @@ try {
|
|||||||
"success" => false,
|
"success" => false,
|
||||||
"message" => "Export failed: " . $e->getMessage(),
|
"message" => "Export failed: " . $e->getMessage(),
|
||||||
"logFiles" => [
|
"logFiles" => [
|
||||||
"step5_create" => $logFileStep5 ?? null,
|
"step5_create" => $logFileStep5 ?? null,
|
||||||
"step6_campioni" => $logFileStep6 ?? null,
|
"step5_2_photos" => $logFilePhotos ?? null,
|
||||||
"step7_patch" => $logFileStep7 ?? null,
|
"step6_campioni" => $logFileStep6 ?? null,
|
||||||
"step10_get" => $logFileStep10 ?? null
|
"step7_patch" => $logFileStep7 ?? null,
|
||||||
|
"step9_1_importa" => $logFileStep91 ?? null,
|
||||||
|
"step10_get" => $logFileStep10 ?? null
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Endpoint: GET api/odata/AnagraficaCertestObject
|
||||||
|
$endpoint = 'AnagraficaCertestObject';
|
||||||
|
|
||||||
|
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
|
||||||
|
$options = []; // es: ['$top' => 100]
|
||||||
|
|
||||||
|
// Debug: salva URL usata
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Chiamata API
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
// Salva il JSON in locale
|
||||||
|
file_put_contents(__DIR__ . '/anagrafica_certest_object_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Endpoint: GET api/odata/AnagraficaCertestService
|
||||||
|
$endpoint = 'AnagraficaCertestService';
|
||||||
|
|
||||||
|
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
|
||||||
|
$options = []; // es: ['$top' => 100]
|
||||||
|
|
||||||
|
// Debug: salva URL usata
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Chiamata API
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
// Salva il JSON in locale
|
||||||
|
file_put_contents(__DIR__ . '/anagrafica_certest_service_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Endpoint per recuperare le Analisi
|
||||||
|
$endpoint = 'Analisi';
|
||||||
|
|
||||||
|
// Opzioni OData
|
||||||
|
$options = [
|
||||||
|
// Restituisce solo i campi principali utili
|
||||||
|
'$select' => 'IdAnalisi,Codice,NomeAnalisi,ClientiAbilitati,MatriciAbilitate,IsGenerico,Tipo,ParentKey,SelezionabileSuWeb',
|
||||||
|
|
||||||
|
// Solo analisi effettivamente selezionabili sul web
|
||||||
|
'$filter' => 'SelezionabileSuWeb eq true',
|
||||||
|
|
||||||
|
// Ordinamento alfabetico per nome analisi
|
||||||
|
'$orderby' => 'NomeAnalisi asc'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Debug: salva URL usato
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_analisi_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Chiamata API
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
// Salva il JSON in locale
|
||||||
|
file_put_contents(__DIR__ . '/analisi_response.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||||
|
|
||||||
|
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/analisi_error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$idCliente = isset($_GET['id_cliente']) ? (int)$_GET['id_cliente'] : 0;
|
||||||
|
if ($idCliente <= 0) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Missing or invalid id_cliente']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Build endpoint with OData $expand WITHOUT encoding '$' as %24
|
||||||
|
$endpoint = "Cliente($idCliente)?\$expand=Responsabili";
|
||||||
|
|
||||||
|
// Debug URL (real final URL)
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$full_url = $base_url . $endpoint;
|
||||||
|
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Call API: options must be empty because expand is already in endpoint
|
||||||
|
$data = $api->get($endpoint, []);
|
||||||
|
|
||||||
|
|
||||||
|
file_put_contents(__DIR__ . '/cliente_responsabili_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
// Return only the list (standard shape used by the frontend)
|
||||||
|
$responsabili = $data['Responsabili'] ?? [];
|
||||||
|
echo json_encode(['value' => $responsabili]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -9,11 +9,28 @@ ini_set('display_errors', '0');
|
|||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$api = VisualLimsApiClient::getInstance();
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv
|
||||||
|
|
||||||
|
// In simulate mode: return fake clients built from idclient values already in datadb.
|
||||||
|
// This ensures client dropdowns auto-select the correct row idclient, which in turn
|
||||||
|
// triggers the ClienteResponsabile select to populate via the mock.
|
||||||
|
if (($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true') {
|
||||||
|
require_once __DIR__ . '/class/db-functions.php';
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
$stmt = $pdo->query("SELECT DISTINCT idclient FROM datadb WHERE idclient IS NOT NULL AND idclient > 0 ORDER BY idclient ASC");
|
||||||
|
$ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
$fakeClients = array_map(fn($id) => [
|
||||||
|
'IdCliente' => (int) $id,
|
||||||
|
'Nominativo' => "Cliente Simulato {$id}",
|
||||||
|
'CodiceCliente' => "SIM_{$id}",
|
||||||
|
], $ids);
|
||||||
|
echo json_encode(['value' => $fakeClients]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Parametri OData
|
// Parametri OData
|
||||||
$params = [
|
$params = [
|
||||||
'$select' => 'IdCliente,Nominativo,CodiceNazioneFatturazione',
|
'$select' => 'IdCliente,Nominativo,CodiceCliente',
|
||||||
'$orderby' => 'Nominativo asc'
|
'$orderby' => 'Nominativo asc'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// Disable PHP error display
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv
|
||||||
|
|
||||||
|
// In simulate mode: return fake clients built from idclient values already in datadb.
|
||||||
|
if (($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true') {
|
||||||
|
require_once __DIR__ . '/class/db-functions.php';
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->query("
|
||||||
|
SELECT DISTINCT idclient
|
||||||
|
FROM datadb
|
||||||
|
WHERE idclient IS NOT NULL
|
||||||
|
AND idclient > 0
|
||||||
|
ORDER BY idclient ASC
|
||||||
|
");
|
||||||
|
|
||||||
|
$ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
$fakeClients = array_map(fn($id) => [
|
||||||
|
'IdCliente' => (int) $id,
|
||||||
|
'Nominativo' => "Cliente Simulato {$id}",
|
||||||
|
'CodiceCliente' => "SIM_{$id}",
|
||||||
|
], $ids);
|
||||||
|
|
||||||
|
echo json_encode(['value' => $fakeClients], JSON_UNESCAPED_UNICODE);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint senza filtri: recupera tutto
|
||||||
|
$endpoint = 'Cliente?$top=50';
|
||||||
|
|
||||||
|
// Funzione per eseguire la chiamata con retry
|
||||||
|
function makeApiRequest($api, $endpoint, $maxRetries = 3)
|
||||||
|
{
|
||||||
|
for ($retry = 0; $retry < $maxRetries; $retry++) {
|
||||||
|
try {
|
||||||
|
$data = $api->get($endpoint);
|
||||||
|
|
||||||
|
// Save response for debug
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/clienti_response.json',
|
||||||
|
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$errorMessage = $e->getMessage();
|
||||||
|
|
||||||
|
// Retry only for specific auth/token related issue
|
||||||
|
if (
|
||||||
|
strpos($errorMessage, 'HTTP 400') !== false &&
|
||||||
|
strpos($errorMessage, 'Cannot persist the object') !== false
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (method_exists($api, 'refreshToken')) {
|
||||||
|
$api->refreshToken();
|
||||||
|
error_log("Tentativo {$retry}: refresh token eseguito per endpoint {$endpoint}");
|
||||||
|
} else {
|
||||||
|
throw new Exception('Il metodo refreshToken() non esiste in VisualLimsApiClient');
|
||||||
|
}
|
||||||
|
} catch (Exception $refreshEx) {
|
||||||
|
error_log("Errore durante il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
throw new Exception("Impossibile eseguire il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(500000); // 500ms
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Massimo numero di tentativi raggiunto per {$endpoint}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Esegui la chiamata
|
||||||
|
$data = makeApiRequest($api, $endpoint);
|
||||||
|
|
||||||
|
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
|
||||||
|
$errorResponse = [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
];
|
||||||
|
|
||||||
|
error_log("Errore in get_clienti.php: " . json_encode($errorResponse, JSON_UNESCAPED_UNICODE));
|
||||||
|
echo json_encode($errorResponse, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
// get_fixed_field_data.php
|
||||||
|
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
$field = $_GET['field'] ?? ''; // es: MoltiplicatorePrezzo, AnagraficaCertestObject, ...
|
||||||
|
|
||||||
|
if (!$field) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Parametro "field" mancante']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv as a side-effect
|
||||||
|
$simulate = ($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true';
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
|
||||||
|
$data = null;
|
||||||
|
$endpoint = null;
|
||||||
|
$cache_file = null;
|
||||||
|
$options = []; // qui puoi aggiungere filtri/ordering per campo se serve
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch ($field) {
|
||||||
|
case 'MoltiplicatorePrezzo':
|
||||||
|
$endpoint = 'MoltiplicatorePrezzi';
|
||||||
|
$cache_file = __DIR__ . '/cache/moltiplicatori_prezzo.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'AnagraficaCertestObject':
|
||||||
|
$endpoint = 'AnagraficaCertestObject';
|
||||||
|
$cache_file = __DIR__ . '/cache/anagrafica_certest_object.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'AnagraficaCertestService':
|
||||||
|
$endpoint = 'AnagraficaCertestService';
|
||||||
|
$cache_file = __DIR__ . '/cache/anagrafica_certest_service.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ClienteResponsabile':
|
||||||
|
$id_cliente = (int)($_GET['id_cliente'] ?? 0);
|
||||||
|
if ($id_cliente <= 0) {
|
||||||
|
if (!$simulate) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Manca o invalido id_cliente']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$id_cliente = 1; // dummy — mock ignores the actual ID
|
||||||
|
}
|
||||||
|
$endpoint = "Cliente($id_cliente)?\$expand=Responsabili";
|
||||||
|
$cache_file = __DIR__ . '/cache/cliente_responsabili_' . $id_cliente . '.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// case 'FuturoCampo5':
|
||||||
|
// $endpoint = 'QualcosaElse';
|
||||||
|
// break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => "Campo non supportato: $field"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caching skipped in simulate mode to avoid polluting real-data cache files
|
||||||
|
if (!$simulate && $cache_file && file_exists($cache_file) && (time() - filemtime($cache_file) < 3600)) { // 1 ora
|
||||||
|
$data = json_decode(file_get_contents($cache_file), true);
|
||||||
|
} else {
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
if (!$simulate && $cache_file) {
|
||||||
|
file_put_contents($cache_file, json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log ultimo URL (opzionale, per debug)
|
||||||
|
$full_url = $base_url . $endpoint . ($options ? '?' . http_build_query($options) : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_urls.log', date('c') . " - $field - $full_url\n", FILE_APPEND);
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . " [$field] " . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Endpoint per recuperare i Moltiplicatori Prezzo
|
||||||
|
// (dal documento: GET api/odata/MoltiplicatorePrezzi)
|
||||||
|
$endpoint = 'MoltiplicatorePrezzi';
|
||||||
|
|
||||||
|
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
|
||||||
|
$options = [
|
||||||
|
'$orderby' => 'Descrizione asc'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Debug: salva URL usata
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$queryParts = [];
|
||||||
|
foreach ($options as $k => $v) {
|
||||||
|
// mantieni il $ nella chiave, encoda solo il valore
|
||||||
|
$queryParts[] = $k . '=' . rawurlencode($v);
|
||||||
|
}
|
||||||
|
$query = implode('&', $queryParts);
|
||||||
|
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Chiamata API
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
// ✅ Force sort locally by "Descrizione" (A→Z)
|
||||||
|
if (isset($data['value']) && is_array($data['value'])) {
|
||||||
|
usort($data['value'], function ($a, $b) {
|
||||||
|
$da = isset($a['Descrizione']) ? trim((string)$a['Descrizione']) : '';
|
||||||
|
$db = isset($b['Descrizione']) ? trim((string)$b['Descrizione']) : '';
|
||||||
|
return strcasecmp($da, $db); // case-insensitive alphabetical
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Salva il JSON in locale
|
||||||
|
file_put_contents(__DIR__ . '/moltiplicatori_prezzo_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/include/headscript.php'; // o il tuo bootstrap standard
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!isset($_GET['iddatadb']) || !is_numeric($_GET['iddatadb'])) {
|
||||||
|
echo json_encode(['success' => true, 'field' => null]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iddatadb = (int)$_GET['iddatadb'];
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// 1) prendo templateid da datadb
|
||||||
|
// 2) cerco max 1 record in template_mapping con is_visible_parts=1
|
||||||
|
$sql = "
|
||||||
|
SELECT tm.field_id, tm.field_label, tm.data_type, tm.has_list
|
||||||
|
FROM datadb d
|
||||||
|
JOIN template_mapping tm ON tm.template_id = d.templateid
|
||||||
|
WHERE d.iddatadb = ?
|
||||||
|
AND tm.is_visible_parts = 1
|
||||||
|
ORDER BY tm.id ASC
|
||||||
|
LIMIT 1
|
||||||
|
";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$iddatadb]);
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'field' => $row ? $row : null
|
||||||
|
]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// Disable PHP error display
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv
|
||||||
|
|
||||||
|
// In simulate mode: return fake users
|
||||||
|
if (($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true') {
|
||||||
|
$fakeUsers = [
|
||||||
|
[
|
||||||
|
'IdUtente' => 1001,
|
||||||
|
'Nominativo' => 'Utente Simulato 1001'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'IdUtente' => 1002,
|
||||||
|
'Nominativo' => 'Utente Simulato 1002'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
echo json_encode(['value' => $fakeUsers]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OData parameters
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Build query string
|
||||||
|
$queryString = http_build_query($params);
|
||||||
|
|
||||||
|
// Final endpoint
|
||||||
|
$endpoint = "Utente?$queryString";
|
||||||
|
|
||||||
|
// Function to execute request with retry
|
||||||
|
function makeApiRequest($api, $endpoint, $maxRetries = 3)
|
||||||
|
{
|
||||||
|
for ($retry = 0; $retry < $maxRetries; $retry++) {
|
||||||
|
try {
|
||||||
|
$data = $api->get($endpoint);
|
||||||
|
|
||||||
|
// Save response for debug
|
||||||
|
file_put_contents(__DIR__ . '/utenti_response.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$errorMessage = $e->getMessage();
|
||||||
|
|
||||||
|
// Retry only on token/auth-related issue
|
||||||
|
if (
|
||||||
|
strpos($errorMessage, 'HTTP 400') !== false &&
|
||||||
|
strpos($errorMessage, 'Cannot persist the object') !== false
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
$api->refreshToken(); // must exist in VisualLimsApiClient
|
||||||
|
error_log("Tentativo $retry: Refresh token eseguito per endpoint $endpoint");
|
||||||
|
} catch (Exception $refreshEx) {
|
||||||
|
error_log("Errore durante il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
throw new Exception("Impossibile eseguire il refresh del token: " . $refreshEx->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(500000); // 500 ms
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Massimo numero di tentativi raggiunto per $endpoint");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute request
|
||||||
|
$data = makeApiRequest($api, $endpoint);
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
|
||||||
|
$errorResponse = [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
];
|
||||||
|
|
||||||
|
error_log("Errore in get_utenti.php: " . json_encode($errorResponse));
|
||||||
|
echo json_encode($errorResponse);
|
||||||
|
}
|
||||||
@@ -59,7 +59,8 @@ foreach ($allMappings as $mapping) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$mainFieldMapping) {
|
if (!$mainFieldMapping) {
|
||||||
$mainFieldMapping = reset(array_filter($allMappings, fn($m) => !$m['is_manual']));
|
$filtered = array_filter($allMappings, fn($m) => !$m['is_manual']);
|
||||||
|
$mainFieldMapping = reset($filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve data from datadb
|
// Retrieve data from datadb
|
||||||
|
|||||||
+1804
-320
File diff suppressed because it is too large
Load Diff
@@ -20,9 +20,10 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !i
|
|||||||
|
|
||||||
$template_id = intval($_POST['template_id']);
|
$template_id = intval($_POST['template_id']);
|
||||||
$selected_rows = array_map('intval', $_POST['selected_rows']);
|
$selected_rows = array_map('intval', $_POST['selected_rows']);
|
||||||
$columns = json_decode($_POST['columns'], true);
|
$columns = json_decode(urldecode($_POST['columns'] ?? '[]'), true);
|
||||||
$rows = json_decode($_POST['rows'], true);
|
$rows = json_decode(urldecode($_POST['rows'] ?? '[]'), true);
|
||||||
$excelrows = json_decode($_POST['excelrows'], true);
|
$excelrows = json_decode(urldecode($_POST['excelrows'] ?? '[]'), true);
|
||||||
|
|
||||||
$newFilename = htmlspecialchars($_POST['filename']);
|
$newFilename = htmlspecialchars($_POST['filename']);
|
||||||
|
|
||||||
$_SESSION['template_id'] = $template_id;
|
$_SESSION['template_id'] = $template_id;
|
||||||
|
|||||||
+121
-40
@@ -121,6 +121,16 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-filters th {
|
||||||
|
background: #ffffff;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-filters input {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<title><?= htmlspecialchars($template['name']) ?> - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title><?= htmlspecialchars($template['name']) ?> - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
@@ -303,57 +313,93 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
function showTable(data) {
|
function showTable(data) {
|
||||||
console.log('Mostro tabella con dati:', data);
|
console.log('Mostro tabella con dati:', data);
|
||||||
let html = `
|
let html = `
|
||||||
<form id="selectRowsForm" action="import_insert.php" method="POST">
|
<form id="selectRowsForm" action="import_insert.php" method="POST">
|
||||||
<input type="hidden" name="template_id" value="${data.template_id}">
|
<input type="hidden" name="template_id" value="${data.template_id}">
|
||||||
<input type="hidden" name="columns" value='${JSON.stringify(data.columns)}'>
|
<input type="hidden" name="columns" value="${encodeURIComponent(JSON.stringify(data.columns))}">
|
||||||
<input type="hidden" name="rows" value='${JSON.stringify(data.rows)}'>
|
<input type="hidden" name="rows" value="${encodeURIComponent(JSON.stringify(data.rows))}">
|
||||||
<input type="hidden" name="excelrows" value='${JSON.stringify(data.excel_data.map(row => row.excelrow))}'>
|
<input type="hidden" name="excelrows" value="${encodeURIComponent(JSON.stringify(data.excel_data.map(r => r.excelrow)))}">
|
||||||
<input type="hidden" name="filename" value="${data.filename}">
|
<input type="hidden" name="filename" value="${data.filename}">
|
||||||
<div class="search-container">
|
|
||||||
<input type="text" id="searchInput" class="form-control" placeholder="Cerca nelle righe...">
|
<!-- TOP BUTTON -->
|
||||||
</div>
|
<div class="d-flex justify-content-end mb-3">
|
||||||
<div class="table-container">
|
<button type="submit" class="btn btn-primary" id="proceedButtonTop" disabled>Prosegui</button>
|
||||||
<table class="table table-striped table-bordered">
|
</div>
|
||||||
<thead>
|
|
||||||
<tr>
|
<div class="table-container">
|
||||||
<th><input type="checkbox" id="selectAll"> Seleziona</th>
|
<table class="table table-striped table-bordered">
|
||||||
${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')}
|
<thead>
|
||||||
</tr>
|
<tr>
|
||||||
</thead>
|
<th><input type="checkbox" id="selectAll"> Seleziona</th>
|
||||||
<tbody>
|
${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')}
|
||||||
${data.excel_data.map((row, index) => `
|
</tr>
|
||||||
<tr>
|
<tr class="column-filters">
|
||||||
<td><input type="checkbox" class="row-checkbox" name="selected_rows[]" value="${index}" data-excelrow="${row.excelrow}"></td>
|
<th></th>
|
||||||
${row.data.map(cell => `<td>${cell}</td>`).join('')}
|
${data.columns.map((col, i) => `
|
||||||
</tr>
|
<th>
|
||||||
`).join('')}
|
<input type="text"
|
||||||
</tbody>
|
class="form-control form-control-sm column-filter"
|
||||||
</table>
|
data-col-index="${i}"
|
||||||
</div>
|
placeholder="Filter...">
|
||||||
<button type="submit" class="btn btn-primary mt-3" id="proceedButton" disabled>Prosegui</button>
|
</th>
|
||||||
</form>
|
`).join('')}
|
||||||
`;
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${data.excel_data.map((row, index) => `
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" name="selected_rows[]" value="${index}" data-excelrow="${row.excelrow}"></td>
|
||||||
|
${row.data.map(cell => `<td>${cell}</td>`).join('')}
|
||||||
|
</tr>
|
||||||
|
`).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- BOTTOM BUTTON -->
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="proceedButtonBottom" disabled>Prosegui</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
tableContainer.innerHTML = html;
|
tableContainer.innerHTML = html;
|
||||||
|
|
||||||
const proceedButton = document.getElementById('proceedButton');
|
const proceedButtonTop = document.getElementById('proceedButtonTop');
|
||||||
|
const proceedButtonBottom = document.getElementById('proceedButtonBottom');
|
||||||
const selectAllCheckbox = document.getElementById('selectAll');
|
const selectAllCheckbox = document.getElementById('selectAll');
|
||||||
const checkboxes = document.querySelectorAll('.row-checkbox');
|
const checkboxes = document.querySelectorAll('.row-checkbox');
|
||||||
|
|
||||||
function updateProceedButton() {
|
function updateProceedButton() {
|
||||||
proceedButton.disabled = !Array.from(checkboxes).some(cb => cb.checked);
|
const enabled = Array.from(checkboxes).some(cb => cb.checked);
|
||||||
|
|
||||||
|
if (proceedButtonTop) proceedButtonTop.disabled = !enabled;
|
||||||
|
if (proceedButtonBottom) proceedButtonBottom.disabled = !enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAllCheckbox.addEventListener('change', function() {
|
selectAllCheckbox.addEventListener('change', function() {
|
||||||
checkboxes.forEach(checkbox => {
|
const visibleRows = Array.from(document.querySelectorAll('.table tbody tr'))
|
||||||
checkbox.checked = this.checked;
|
.filter(row => row.style.display !== 'none');
|
||||||
|
|
||||||
|
visibleRows.forEach(row => {
|
||||||
|
const checkbox = row.querySelector('.row-checkbox');
|
||||||
|
if (checkbox) {
|
||||||
|
checkbox.checked = this.checked;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateProceedButton();
|
updateProceedButton();
|
||||||
});
|
});
|
||||||
|
|
||||||
checkboxes.forEach(checkbox => {
|
checkboxes.forEach(checkbox => {
|
||||||
checkbox.addEventListener('change', function() {
|
checkbox.addEventListener('change', function() {
|
||||||
console.log('Checkbox changed, checked:', this.checked, 'excelrow:', this.dataset.excelrow);
|
console.log('Checkbox changed, checked:', this.checked, 'excelrow:', this.dataset.excelrow);
|
||||||
selectAllCheckbox.checked = Array.from(checkboxes).every(cb => cb.checked);
|
|
||||||
|
const visibleCheckboxes = Array.from(document.querySelectorAll('.table tbody tr'))
|
||||||
|
.filter(row => row.style.display !== 'none')
|
||||||
|
.map(row => row.querySelector('.row-checkbox'))
|
||||||
|
.filter(cb => cb !== null);
|
||||||
|
|
||||||
|
selectAllCheckbox.checked =
|
||||||
|
visibleCheckboxes.length > 0 &&
|
||||||
|
visibleCheckboxes.every(cb => cb.checked);
|
||||||
|
|
||||||
updateProceedButton();
|
updateProceedButton();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -393,14 +439,49 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchInput = document.getElementById('searchInput');
|
|
||||||
const rows = document.querySelectorAll('.table tbody tr');
|
const rows = document.querySelectorAll('.table tbody tr');
|
||||||
|
const filterInputs = document.querySelectorAll('.column-filter');
|
||||||
|
|
||||||
searchInput.addEventListener('input', function() {
|
// Stato filtri: key = colIndex, value = testo
|
||||||
const searchTerm = this.value.toLowerCase();
|
const activeFilters = {};
|
||||||
|
|
||||||
|
function applyColumnFilters() {
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
const text = Array.from(row.cells).slice(1).map(cell => cell.textContent.toLowerCase()).join(' ');
|
let visible = true;
|
||||||
row.style.display = text.includes(searchTerm) ? '' : 'none';
|
|
||||||
|
for (const [colIndexStr, filterValue] of Object.entries(activeFilters)) {
|
||||||
|
const colIndex = parseInt(colIndexStr, 10);
|
||||||
|
const cell = row.cells[colIndex + 1];
|
||||||
|
|
||||||
|
const cellText = (cell?.textContent || '').toLowerCase();
|
||||||
|
const searchText = (filterValue || '').toLowerCase().trim();
|
||||||
|
|
||||||
|
if (searchText && !cellText.includes(searchText)) {
|
||||||
|
visible = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
row.style.display = visible ? '' : 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
const visibleCheckboxes = Array.from(document.querySelectorAll('.table tbody tr'))
|
||||||
|
.filter(row => row.style.display !== 'none')
|
||||||
|
.map(row => row.querySelector('.row-checkbox'))
|
||||||
|
.filter(cb => cb !== null);
|
||||||
|
|
||||||
|
selectAllCheckbox.checked =
|
||||||
|
visibleCheckboxes.length > 0 &&
|
||||||
|
visibleCheckboxes.every(cb => cb.checked);
|
||||||
|
|
||||||
|
updateProceedButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
filterInputs.forEach(input => {
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
const colIndex = this.dataset.colIndex; // string
|
||||||
|
activeFilters[colIndex] = this.value;
|
||||||
|
applyColumnFilters();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ $nameuser = $user->present()->first_name;
|
|||||||
$surnameuser = $user->present()->last_name;
|
$surnameuser = $user->present()->last_name;
|
||||||
$emailuser = $user->present()->email;
|
$emailuser = $user->present()->email;
|
||||||
$avatar = $user->present()->avatar;
|
$avatar = $user->present()->avatar;
|
||||||
|
$lims_user_id = $user->lims_user_id ?? '';
|
||||||
|
$lims_global_user_id = $user->lims_global_user_id ?? '';
|
||||||
|
|
||||||
$kindofrole = $user->present()->role_id;
|
$kindofrole = $user->present()->role_id;
|
||||||
|
|
||||||
@@ -35,8 +37,6 @@ $kindofrole = $user->present()->role_id;
|
|||||||
//$iduserlogin="1";
|
//$iduserlogin="1";
|
||||||
//$nameuser="Claudio";
|
//$nameuser="Claudio";
|
||||||
//$emailuser="info@claudiosironi.com";
|
//$emailuser="info@claudiosironi.com";
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
if (session_status() == PHP_SESSION_NONE) {
|
if (session_status() == PHP_SESSION_NONE) {
|
||||||
session_start();
|
session_start();
|
||||||
}
|
}
|
||||||
@@ -49,13 +49,8 @@ $_SESSION["emailuser"] = $emailuser;
|
|||||||
$_SESSION["photouser"] = $avatar;
|
$_SESSION["photouser"] = $avatar;
|
||||||
$photouser = $_SESSION["photouser"];
|
$photouser = $_SESSION["photouser"];
|
||||||
$photousername = basename($avatar);
|
$photousername = basename($avatar);
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
<?php //include files
|
|
||||||
|
|
||||||
|
//include files
|
||||||
require_once(__DIR__ . '/../../languages/en/general.php');
|
require_once(__DIR__ . '/../../languages/en/general.php');
|
||||||
|
|
||||||
//include("generalsettings.php");
|
//include("generalsettings.php");
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php include('include/headscript.php');
|
<?php include('include/headscript.php');
|
||||||
|
|
||||||
// Recupera tutte le routine dal database
|
// Retrieve all routines from database
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
$stmt = $pdo->prepare("SELECT * FROM routine");
|
$stmt = $pdo->prepare("SELECT * FROM routine");
|
||||||
@@ -18,26 +18,29 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<title>Insert XLS Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Insert Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
|
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
|
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="mb-0">Insert new XLS Template</h5>
|
<h5 class="mb-0">Insert New Template</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-2">Fill the following form in order to create a new import XLS template</p>
|
<p class="mb-2">Fill the following form in order to create a new import template</p>
|
||||||
<p class="mb-2">Mandatory Fields</p>
|
<p class="mb-2">Mandatory Fields</p>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li>Template Name</li>
|
<li>Template Name</li>
|
||||||
<li>Row Header and Column Header: where the title of the excel starts</li>
|
<li>Source Type</li>
|
||||||
<li>Schema and client</li>
|
<li>Schema and Client</li>
|
||||||
|
<li>Row Header and Column Header only for XLS templates</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,22 +53,33 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<form id="insertTemplateForm" method="POST">
|
<form id="insertTemplateForm" method="POST">
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($templatename, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="name" class="form-control" required>
|
<input type="text" name="name" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label">Source Type *</label>
|
||||||
<input type="number" name="header_row" class="form-control" required>
|
<select name="source_type" id="sourceType" class="form-control" required>
|
||||||
|
<option value="XLS" selected>XLS</option>
|
||||||
|
<option value="API">API</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">Choose the source used by this template</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3" id="headerRowWrapper">
|
||||||
|
<label class="form-label"><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
|
<input type="number" name="header_row" id="headerRow" class="form-control" value="1" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="startColumnWrapper">
|
||||||
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
<label class="form-label"><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?> *</label>
|
||||||
<input type="text" name="start_column" class="form-control" required>
|
<input type="text" name="start_column" id="startColumn" class="form-control" value="A" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -86,12 +100,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Background Color</label>
|
<label class="form-label">Button Background Color</label>
|
||||||
<input type="color" name="button_bg_color" class="form-control" value="#007bff">
|
<input type="color" name="button_bg_color" class="form-control form-control-color" value="#007bff">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Text Color</label>
|
<label class="form-label">Button Text Color</label>
|
||||||
<input type="color" name="button_text_color" class="form-control" value="#ffffff">
|
<input type="color" name="button_text_color" class="form-control form-control-color" value="#ffffff">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -125,6 +139,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</option>
|
</option>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div id="routineDetails" class="mt-2" style="display: none;">
|
<div id="routineDetails" class="mt-2" style="display: none;">
|
||||||
<h6>Routine Details</h6>
|
<h6>Routine Details</h6>
|
||||||
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
<p><strong>Name:</strong> <span id="routineName"></span></p>
|
||||||
@@ -142,8 +157,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
@@ -167,6 +184,12 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const routineAction2 = document.getElementById("routineAction2");
|
const routineAction2 = document.getElementById("routineAction2");
|
||||||
const routineAction3 = document.getElementById("routineAction3");
|
const routineAction3 = document.getElementById("routineAction3");
|
||||||
|
|
||||||
|
const sourceType = document.getElementById("sourceType");
|
||||||
|
const headerRowWrapper = document.getElementById("headerRowWrapper");
|
||||||
|
const startColumnWrapper = document.getElementById("startColumnWrapper");
|
||||||
|
const headerRow = document.getElementById("headerRow");
|
||||||
|
const startColumn = document.getElementById("startColumn");
|
||||||
|
|
||||||
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
||||||
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
||||||
return;
|
return;
|
||||||
@@ -187,30 +210,66 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
allowClear: true
|
allowClear: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateSourceFields() {
|
||||||
|
const selectedSource = sourceType.value;
|
||||||
|
|
||||||
|
if (selectedSource === 'API') {
|
||||||
|
headerRowWrapper.style.opacity = '0.6';
|
||||||
|
startColumnWrapper.style.opacity = '0.6';
|
||||||
|
|
||||||
|
headerRow.required = false;
|
||||||
|
startColumn.required = false;
|
||||||
|
|
||||||
|
headerRow.disabled = true;
|
||||||
|
startColumn.disabled = true;
|
||||||
|
} else {
|
||||||
|
headerRowWrapper.style.opacity = '1';
|
||||||
|
startColumnWrapper.style.opacity = '1';
|
||||||
|
|
||||||
|
headerRow.required = true;
|
||||||
|
startColumn.required = true;
|
||||||
|
|
||||||
|
headerRow.disabled = false;
|
||||||
|
startColumn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceType.addEventListener('change', updateSourceFields);
|
||||||
|
updateSourceFields();
|
||||||
|
|
||||||
async function loadClients() {
|
async function loadClients() {
|
||||||
try {
|
try {
|
||||||
clientLoadingStatus.style.display = 'inline';
|
clientLoadingStatus.style.display = 'inline';
|
||||||
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_clienti.php", {
|
const response = await fetch("get_clienti.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("clientSelect");
|
const select = document.getElementById("clientSelect");
|
||||||
select.innerHTML = '<option value="">Select a client...</option>';
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
|
||||||
data.value.forEach(client => {
|
data.value.forEach(client => {
|
||||||
const nome = client.Nominativo || "Nome non disponibile";
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
const id = client.IdCliente || "ID non disponibile";
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
clientLoadingStatus.textContent = "Clienti caricati.";
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Impossibile caricare i clienti: " + error.message,
|
text: "Impossibile caricare i clienti: " + error.message,
|
||||||
@@ -226,26 +285,43 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
try {
|
try {
|
||||||
schemaLoadingStatus.style.display = 'inline';
|
schemaLoadingStatus.style.display = 'inline';
|
||||||
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_schemi.php", {
|
const response = await fetch("get_schemi.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
const select = document.getElementById("schemaSelect");
|
const select = document.getElementById("schemaSelect");
|
||||||
select.innerHTML = '<option value="">Select a schema...</option>';
|
select.innerHTML = '<option value="">Select a schema...</option>';
|
||||||
data.value.forEach(schema => {
|
|
||||||
|
const sortedSchemas = [...data.value].sort((a, b) => {
|
||||||
|
const nomeA = (a.Nome || "").trim().toLowerCase();
|
||||||
|
const nomeB = (b.Nome || "").trim().toLowerCase();
|
||||||
|
return nomeA.localeCompare(nomeB, 'it', {
|
||||||
|
sensitivity: 'base'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
sortedSchemas.forEach(schema => {
|
||||||
const nome = schema.Nome || "Nome non disponibile";
|
const nome = schema.Nome || "Nome non disponibile";
|
||||||
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
||||||
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
schemaLoadingStatus.textContent = "Schemi caricati.";
|
schemaLoadingStatus.textContent = "Schemi caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Impossibile caricare gli schemi: " + error.message,
|
text: "Impossibile caricare gli schemi: " + error.message,
|
||||||
@@ -270,6 +346,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData();
|
loadData();
|
||||||
|
|
||||||
const routines = <?php echo json_encode($routines); ?>;
|
const routines = <?php echo json_encode($routines); ?>;
|
||||||
@@ -277,8 +354,10 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
function updateRoutineDetails() {
|
function updateRoutineDetails() {
|
||||||
const selectedId = routineSelect.value;
|
const selectedId = routineSelect.value;
|
||||||
routineDetails.style.display = selectedId ? 'block' : 'none';
|
routineDetails.style.display = selectedId ? 'block' : 'none';
|
||||||
|
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
const routine = routines.find(r => r.idroutine == selectedId);
|
const routine = routines.find(r => r.idroutine == selectedId);
|
||||||
|
|
||||||
if (routine) {
|
if (routine) {
|
||||||
routineName.textContent = routine.name || 'N/A';
|
routineName.textContent = routine.name || 'N/A';
|
||||||
routineDescription.textContent = routine.description || 'N/A';
|
routineDescription.textContent = routine.description || 'N/A';
|
||||||
@@ -300,6 +379,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
routineAction3.textContent = '';
|
routineAction3.textContent = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routineSelect.addEventListener('change', updateRoutineDetails);
|
routineSelect.addEventListener('change', updateRoutineDetails);
|
||||||
updateRoutineDetails();
|
updateRoutineDetails();
|
||||||
|
|
||||||
@@ -350,6 +430,7 @@ $routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append("idschema", schemaId);
|
formData.append("idschema", schemaId);
|
||||||
formData.append("schemaname", schemaName);
|
formData.append("schemaname", schemaName);
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,57 @@ if (!$iddatadb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT id, iddatadb, part_number, part_description, idmatrice, note, dateexpiry FROM identification_parts WHERE iddatadb = :iddatadb ORDER BY part_number ASC");
|
// 1) prendo templateid da datadb
|
||||||
$stmt->execute([':iddatadb' => $iddatadb]);
|
$stmtTpl = $pdo->prepare("SELECT templateid FROM datadb WHERE iddatadb = :iddatadb LIMIT 1");
|
||||||
|
$stmtTpl->execute([':iddatadb' => $iddatadb]);
|
||||||
|
$templateid = $stmtTpl->fetchColumn();
|
||||||
|
|
||||||
|
// 2) prendo (max 1) field_id visibile in parts
|
||||||
|
$extraFieldId = null;
|
||||||
|
if ($templateid) {
|
||||||
|
$stmtEF = $pdo->prepare("SELECT field_id FROM template_mapping WHERE template_id = :templateid AND is_visible_parts = 1 ORDER BY id ASC LIMIT 1");
|
||||||
|
$stmtEF->execute([':templateid' => $templateid]);
|
||||||
|
$extraFieldId = $stmtEF->fetchColumn();
|
||||||
|
if ($extraFieldId !== false) $extraFieldId = (int)$extraFieldId;
|
||||||
|
else $extraFieldId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) carico parts + join su tabella figlia
|
||||||
|
if ($extraFieldId) {
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT
|
||||||
|
p.id, p.iddatadb, p.part_number, p.part_description, p.idmatrice, p.note, p.dateexpiry,
|
||||||
|
cf.value_id AS extra_value_id,
|
||||||
|
cf.value_text AS extra_value_text
|
||||||
|
FROM identification_parts p
|
||||||
|
LEFT JOIN identification_parts_customfields cf
|
||||||
|
ON cf.part_id = p.id AND cf.field_id = :extraFieldId
|
||||||
|
WHERE p.iddatadb = :iddatadb
|
||||||
|
ORDER BY p.part_number ASC
|
||||||
|
");
|
||||||
|
$stmt->execute([
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':extraFieldId' => $extraFieldId
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT id, iddatadb, part_number, part_description, idmatrice, note, dateexpiry,
|
||||||
|
NULL AS extra_value_id, NULL AS extra_value_text
|
||||||
|
FROM identification_parts
|
||||||
|
WHERE iddatadb = :iddatadb
|
||||||
|
ORDER BY part_number ASC
|
||||||
|
");
|
||||||
|
$stmt->execute([':iddatadb' => $iddatadb]);
|
||||||
|
}
|
||||||
|
|
||||||
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
echo json_encode(['success' => true, 'parts' => $parts]);
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'parts' => $parts,
|
||||||
|
'extra_field_id' => $extraFieldId,
|
||||||
|
'debug_sql' => ($extraFieldId ? 'WITH_CF_JOIN' : 'NO_CF')
|
||||||
|
]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
|
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
// Recupera l'ID dell'utente loggato
|
||||||
|
$user_id = $iduserlogin ?? 1;
|
||||||
|
|
||||||
|
if (!$user_id) {
|
||||||
|
echo json_encode(['success' => false, 'message' => "ID dell'utente autenticato mancante"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"SELECT DISTINCT q.*
|
||||||
|
FROM quotations q
|
||||||
|
INNER JOIN identification_parts ip
|
||||||
|
ON ip.idquotations = q.id
|
||||||
|
AND ip.iddatadb IS NULL
|
||||||
|
WHERE q.iduser = :iduser"
|
||||||
|
);
|
||||||
|
$stmt->execute([':iduser' => $user_id]);
|
||||||
|
$quotations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'quotations' => $quotations]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento delle quotations: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
CAMPIONE #0
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 563528,
|
||||||
|
"Matrice": 3879,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "Parte AAA",
|
||||||
|
"ConsegnaRichiesta": "2026-01-30"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 734582,
|
||||||
|
"CodiceCampione": "10978",
|
||||||
|
"CodiceCampioneWeb": "10978",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-11T14:10:02.1595894+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-01-30T00:00:00+01:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "Parte AAA",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #1
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 563528,
|
||||||
|
"Matrice": 3879,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "PARE BBB",
|
||||||
|
"ConsegnaRichiesta": "2026-01-30"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 734583,
|
||||||
|
"CodiceCampione": "10979",
|
||||||
|
"CodiceCampioneWeb": "10979",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-11T14:10:03.9972635+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-01-30T00:00:00+01:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "PARE BBB",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(563528)/ImportaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"IdUtente": 285
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 563528,
|
||||||
|
"CodiceCommessa": "26C0029",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Elaborata",
|
||||||
|
"DataCreazioneWeb": "2026-03-11T14:10:00.897+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0029",
|
||||||
|
"DataInviatoWeb": "2026-03-11T14:10:11.76+01:00",
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb"
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
Photos for CommessaWeb 563528 (iddatadb=1259):
|
||||||
|
Total photos found: 2, campioni: 2
|
||||||
|
|
||||||
|
=== Campione 734582 (main) ===
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(734582)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1259-20260311130930-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1779561,
|
||||||
|
"FileName": "1259-20260311130930-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-11T14:10:06.7051549+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(734582)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1259-20260311130930-1e672dd9-5420-4432-b422-02d8d271c178.jpg'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1779562,
|
||||||
|
"FileName": "1259-20260311130930-1e672dd9-5420-4432-b422-02d8d271c178.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-11T14:10:08.5442313+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(563528)/InviaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 563528,
|
||||||
|
"CodiceCommessa": "26C0029",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-11T14:10:00.897+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0029",
|
||||||
|
"DataInviatoWeb": "2026-03-11T14:10:11.7602299+01:00",
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb"
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
curl --location --request PATCH 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(563528)' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"CommesseCustomFields": [
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254249,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254250,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254251,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254252,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254253,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254254,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254260,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254261,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254262,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254264,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254265,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254266,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254267,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254268,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254228,
|
||||||
|
"Valore": "13526"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254229,
|
||||||
|
"Valore": "20262"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254230,
|
||||||
|
"Valore": "ART. PEACH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254269,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254270,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254271,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254272,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254273,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254274,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254275,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254276,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254277,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254278,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254279,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254280,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254281,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254231,
|
||||||
|
"Valore": "L209A4M00130M7280"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254232,
|
||||||
|
"Valore": "BLACK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254233,
|
||||||
|
"Valore": "PE007J"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254234,
|
||||||
|
"Valore": "262"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254235,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254236,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254237,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254238,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254239,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254240,
|
||||||
|
"Valore": "Oggi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254241,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254242,
|
||||||
|
"Valore": "MONCLER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254243,
|
||||||
|
"Valore": "236"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254244,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254245,
|
||||||
|
"Valore": "BBB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254246,
|
||||||
|
"Valore": "solocla"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254247,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254248,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254255,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254256,
|
||||||
|
"Valore": "MONCLER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254257,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254258,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254259,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23254263,
|
||||||
|
"Valore": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
null
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
CAMPIONE #0
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 564663,
|
||||||
|
"Matrice": 3028,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "Parte 1",
|
||||||
|
"ConsegnaRichiesta": "2026-03-31"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736244,
|
||||||
|
"CodiceCampione": "11004",
|
||||||
|
"CodiceCampioneWeb": "11004",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-17T14:52:30.3143366+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-03-31T00:00:00+02:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "Parte 1",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #1
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 564663,
|
||||||
|
"Matrice": 3028,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "Parte 2",
|
||||||
|
"ConsegnaRichiesta": "2026-03-31"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736245,
|
||||||
|
"CodiceCampione": "11005",
|
||||||
|
"CodiceCampioneWeb": "11005",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-17T14:52:31.9631757+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-03-31T00:00:00+02:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "Parte 2",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(564663)/ImportaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"IdUtente": 285
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564663,
|
||||||
|
"CodiceCommessa": "26C0059",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Elaborata",
|
||||||
|
"DataCreazioneWeb": "2026-03-17T14:52:29.347+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0059",
|
||||||
|
"DataInviatoWeb": "2026-03-17T14:52:38.99+01:00",
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
Photos for CommessaWeb 564663 (iddatadb=1268):
|
||||||
|
Total photos found: 2, campioni: 2
|
||||||
|
|
||||||
|
=== Campione 736244 (main) ===
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(736244)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1268-20260317134828-1e672dd9-5420-4432-b422-02d8d271c178.jpg' \
|
||||||
|
--form 'StampaNelRapporto=true' \
|
||||||
|
--form 'PrimaPagina=true'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1784768,
|
||||||
|
"FileName": "1268-20260317134828-1e672dd9-5420-4432-b422-02d8d271c178.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-17T14:52:33.9816658+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(736244)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1268-20260317134828-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg' \
|
||||||
|
--form 'StampaNelRapporto=false' \
|
||||||
|
--form 'PrimaPagina=false'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1784769,
|
||||||
|
"FileName": "1268-20260317134828-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-17T14:52:35.2759882+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(564663)/InviaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564663,
|
||||||
|
"CodiceCommessa": "26C0059",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-17T14:52:29.347+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0059",
|
||||||
|
"DataInviatoWeb": "2026-03-17T14:52:38.9894528+01:00",
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
curl --location --request PATCH 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(564663)' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"CommesseCustomFields": [
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308665,
|
||||||
|
"Valore": "2026-03-17T13:52:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308666,
|
||||||
|
"Valore": "13:52"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308667,
|
||||||
|
"Valore": "9299"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308668,
|
||||||
|
"Valore": "2026-03-17T13:52:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308669,
|
||||||
|
"Valore": "aaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308670,
|
||||||
|
"Valore": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308676,
|
||||||
|
"Valore": "673"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308677,
|
||||||
|
"Valore": "674"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308678,
|
||||||
|
"Valore": "4410"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308680,
|
||||||
|
"Valore": "1468"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308681,
|
||||||
|
"Valore": "1604"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308682,
|
||||||
|
"Valore": "12875"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308683,
|
||||||
|
"Valore": "8755"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308684,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308644,
|
||||||
|
"Valore": "13497"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308645,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308646,
|
||||||
|
"Valore": "Example Description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308685,
|
||||||
|
"Valore": "1892"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308686,
|
||||||
|
"Valore": "1111"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308687,
|
||||||
|
"Valore": "2026-03-02T13:52:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308688,
|
||||||
|
"Valore": "2026-03-17T13:52:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308689,
|
||||||
|
"Valore": "2026-03-17T13:52:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308690,
|
||||||
|
"Valore": "1978"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308691,
|
||||||
|
"Valore": "13:52"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308692,
|
||||||
|
"Valore": "14:44"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308693,
|
||||||
|
"Valore": "14:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308694,
|
||||||
|
"Valore": "2026-03-17T13:52:36+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308695,
|
||||||
|
"Valore": "8596"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308696,
|
||||||
|
"Valore": "8600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308697,
|
||||||
|
"Valore": "8605"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308647,
|
||||||
|
"Valore": "L209A4M00130M7280"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308648,
|
||||||
|
"Valore": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308649,
|
||||||
|
"Valore": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308650,
|
||||||
|
"Valore": "264"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308651,
|
||||||
|
"Valore": "1589"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308652,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308653,
|
||||||
|
"Valore": "3055"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308654,
|
||||||
|
"Valore": "aaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308655,
|
||||||
|
"Valore": "qqq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308656,
|
||||||
|
"Valore": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308657,
|
||||||
|
"Valore": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308658,
|
||||||
|
"Valore": "qqq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308659,
|
||||||
|
"Valore": "236"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308660,
|
||||||
|
"Valore": "1208"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308661,
|
||||||
|
"Valore": "ciao"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308662,
|
||||||
|
"Valore": "bbb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308663,
|
||||||
|
"Valore": "12234"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308664,
|
||||||
|
"Valore": "MONCLER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308671,
|
||||||
|
"Valore": "L209A4M00130M7280 - PACEY2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308672,
|
||||||
|
"Valore": "4678"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308673,
|
||||||
|
"Valore": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308674,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308675,
|
||||||
|
"Valore": "2450"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23308679,
|
||||||
|
"Valore": "744"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
null
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
CAMPIONE #0
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 564817,
|
||||||
|
"Matrice": 3028,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "AAA",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736487,
|
||||||
|
"CodiceCampione": "11016",
|
||||||
|
"CodiceCampioneWeb": "11016",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:03.4537462+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29T00:00:00+01:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "AAA",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #1
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 564817,
|
||||||
|
"Matrice": 3028,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "CCC",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736488,
|
||||||
|
"CodiceCampione": "11017",
|
||||||
|
"CodiceCampioneWeb": "11017",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:04.8623753+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29T00:00:00+01:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "CCC",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #2
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 564817,
|
||||||
|
"Matrice": 3028,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "DDD",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736489,
|
||||||
|
"CodiceCampione": "11018",
|
||||||
|
"CodiceCampioneWeb": "11018",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:06.2840533+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29T00:00:00+01:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "DDD",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #3
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 564817,
|
||||||
|
"Matrice": 3028,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "EEE",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736490,
|
||||||
|
"CodiceCampione": "11019",
|
||||||
|
"CodiceCampioneWeb": "11019",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:07.8853452+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-01-29T00:00:00+01:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "EEE",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(564817)/ImportaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"IdUtente": 285
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564817,
|
||||||
|
"CodiceCommessa": "26C0071",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Elaborata",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:02.187+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0071",
|
||||||
|
"DataInviatoWeb": "2026-03-18T10:54:14.727+01:00",
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
Photos for CommessaWeb 564817 (iddatadb=1270):
|
||||||
|
Total photos found: 2, campioni: 4
|
||||||
|
|
||||||
|
=== Campione 736487 (main) ===
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(736487)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1270-20260318095305-1e672dd9-5420-4432-b422-02d8d271c178.jpg' \
|
||||||
|
--form 'StampaNelRapporto=true' \
|
||||||
|
--form 'PrimaPagina=true'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1785492,
|
||||||
|
"FileName": "1270-20260318095305-1e672dd9-5420-4432-b422-02d8d271c178.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-18T10:54:09.5438326+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(736487)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1270-20260318095305-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg' \
|
||||||
|
--form 'StampaNelRapporto=false' \
|
||||||
|
--form 'PrimaPagina=false'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1785493,
|
||||||
|
"FileName": "1270-20260318095305-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-18T10:54:10.8237002+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(564817)/InviaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564817,
|
||||||
|
"CodiceCommessa": "26C0071",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:02.187+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0071",
|
||||||
|
"DataInviatoWeb": "2026-03-18T10:54:14.7252132+01:00",
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
curl --location --request PATCH 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(564817)' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"CommesseCustomFields": [
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315543,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315544,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315545,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315546,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315547,
|
||||||
|
"Valore": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315548,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315554,
|
||||||
|
"Valore": "673"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315555,
|
||||||
|
"Valore": "674"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315556,
|
||||||
|
"Valore": "669"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315558,
|
||||||
|
"Valore": "1469"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315559,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315560,
|
||||||
|
"Valore": "12875"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315561,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315562,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315522,
|
||||||
|
"Valore": "13497"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315523,
|
||||||
|
"Valore": "20262"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315524,
|
||||||
|
"Valore": "ART. PEACH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315563,
|
||||||
|
"Valore": "1892"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315564,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315565,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315566,
|
||||||
|
"Valore": "2026-03-18T09:54:11+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315567,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315568,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315569,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315570,
|
||||||
|
"Valore": "09:53"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315571,
|
||||||
|
"Valore": "10:37"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315572,
|
||||||
|
"Valore": "2026-03-18T09:54:11+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315573,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315574,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315575,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315525,
|
||||||
|
"Valore": "L209A4M00130M7280"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315526,
|
||||||
|
"Valore": "BLACK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315527,
|
||||||
|
"Valore": "PE007J"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315528,
|
||||||
|
"Valore": "264"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315529,
|
||||||
|
"Valore": "420"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315530,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315531,
|
||||||
|
"Valore": "15357"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315532,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315533,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315534,
|
||||||
|
"Valore": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315535,
|
||||||
|
"Valore": "RM-ACC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315536,
|
||||||
|
"Valore": " CONCERIA M2 SRL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315537,
|
||||||
|
"Valore": "344"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315538,
|
||||||
|
"Valore": "520"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315539,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315540,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315541,
|
||||||
|
"Valore": "Not provided"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315542,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315549,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315550,
|
||||||
|
"Valore": "4678"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315551,
|
||||||
|
"Valore": "Leather&amp;Fur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315552,
|
||||||
|
"Valore": "278"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315553,
|
||||||
|
"Valore": "2089"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23315557,
|
||||||
|
"Valore": "745"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
null
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
CAMPIONE #0
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 565085,
|
||||||
|
"Matrice": 7714,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "Parte AAA",
|
||||||
|
"ConsegnaRichiesta": "2026-04-08"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736899,
|
||||||
|
"CodiceCampione": "11038",
|
||||||
|
"CodiceCampioneWeb": "11038",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-19T10:03:19.8547279+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-04-08T00:00:00+02:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "Parte AAA",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #1
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 565085,
|
||||||
|
"Matrice": 7714,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "Parte BBB",
|
||||||
|
"ConsegnaRichiesta": "2026-04-08"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736900,
|
||||||
|
"CodiceCampione": "11039",
|
||||||
|
"CodiceCampioneWeb": "11039",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-19T10:03:22.0431135+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-04-08T00:00:00+02:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "Parte BBB",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #2
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 565085,
|
||||||
|
"Matrice": 7714,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "Parte CCC",
|
||||||
|
"ConsegnaRichiesta": "2026-04-08"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#Campione\/$entity",
|
||||||
|
"IdCampione": 736901,
|
||||||
|
"CodiceCampione": "11040",
|
||||||
|
"CodiceCampioneWeb": "11040",
|
||||||
|
"StatoCampione": "Nuovo",
|
||||||
|
"DataCreazioneWeb": "2026-03-19T10:03:23.6170597+01:00",
|
||||||
|
"RiferimentoWeb": "",
|
||||||
|
"ConsegnaRichiesta": "2026-04-08T00:00:00+02:00",
|
||||||
|
"DataAccettazioneLims": null,
|
||||||
|
"Riferimento": null,
|
||||||
|
"NoteWeb": "Parte CCC",
|
||||||
|
"GruppiRicercati": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(565085)/ImportaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"IdUtente": 285
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 565085,
|
||||||
|
"CodiceCommessa": "26C0089",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Elaborata",
|
||||||
|
"DataCreazioneWeb": "2026-03-19T10:03:18.653+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0089",
|
||||||
|
"DataInviatoWeb": "2026-03-19T10:03:30.603+01:00",
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
Photos for CommessaWeb 565085 (iddatadb=1279):
|
||||||
|
Total photos found: 2, campioni: 3
|
||||||
|
|
||||||
|
=== Campione 736899 (main) ===
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(736899)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1279-20260319090037-1e672dd9-5420-4432-b422-02d8d271c178.jpg' \
|
||||||
|
--form 'StampaNelRapporto=true' \
|
||||||
|
--form 'PrimaPagina=true'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1786602,
|
||||||
|
"FileName": "1279-20260319090037-1e672dd9-5420-4432-b422-02d8d271c178.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-19T10:03:25.2757049+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione(736899)/UploadCampioneFile' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1279-20260319090037-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg' \
|
||||||
|
--form 'StampaNelRapporto=false' \
|
||||||
|
--form 'PrimaPagina=false'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CampioneFiles\/$entity",
|
||||||
|
"IdCampioneFile": 1786603,
|
||||||
|
"FileName": "1279-20260319090037-104a2ca5-8a4c-4df8-b2ca-a28f518b7b25.jpg",
|
||||||
|
"Web": false,
|
||||||
|
"AllegaAlRapporto": false,
|
||||||
|
"StampaNelRapporto": false,
|
||||||
|
"ReportGermania": false,
|
||||||
|
"PrimaPagina": false,
|
||||||
|
"Duplica": false,
|
||||||
|
"LastUpdate": "2026-03-19T10:03:26.7566613+01:00",
|
||||||
|
"Titolo": null
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(565085)/InviaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 565085,
|
||||||
|
"CodiceCommessa": "26C0089",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-19T10:03:18.653+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0089",
|
||||||
|
"DataInviatoWeb": "2026-03-19T10:03:30.6022436+01:00",
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
curl --location --request PATCH 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(565085)' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"CommesseCustomFields": [
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328248,
|
||||||
|
"Valore": "18/03/2026"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328249,
|
||||||
|
"Valore": "09:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328250,
|
||||||
|
"Valore": "9299"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328251,
|
||||||
|
"Valore": "17/03/2026"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328252,
|
||||||
|
"Valore": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328253,
|
||||||
|
"Valore": "5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328259,
|
||||||
|
"Valore": "673"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328260,
|
||||||
|
"Valore": "674"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328261,
|
||||||
|
"Valore": "669"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328263,
|
||||||
|
"Valore": "1469"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328264,
|
||||||
|
"Valore": "1604"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328265,
|
||||||
|
"Valore": "12875"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328266,
|
||||||
|
"Valore": "8755"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328267,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328227,
|
||||||
|
"Valore": "13497"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328228,
|
||||||
|
"Valore": "20262"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328229,
|
||||||
|
"Valore": "ART. PEACH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328268,
|
||||||
|
"Valore": "1892"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328269,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328270,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328271,
|
||||||
|
"Valore": "19/03/2026"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328272,
|
||||||
|
"Valore": "18/03/2026"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328273,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328274,
|
||||||
|
"Valore": "09:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328275,
|
||||||
|
"Valore": "09:03"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328276,
|
||||||
|
"Valore": "09:58"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328277,
|
||||||
|
"Valore": "19/03/2026"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328278,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328279,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328280,
|
||||||
|
"Valore": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328230,
|
||||||
|
"Valore": "L209B4M00110M7280"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328231,
|
||||||
|
"Valore": "BLACK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328232,
|
||||||
|
"Valore": "PE007J"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328233,
|
||||||
|
"Valore": "264"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328234,
|
||||||
|
"Valore": "420"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328235,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328236,
|
||||||
|
"Valore": "3055"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328237,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328238,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328239,
|
||||||
|
"Valore": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328240,
|
||||||
|
"Valore": "RM-ACC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328241,
|
||||||
|
"Valore": "\u00a0CONCERIA M2 SRL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328242,
|
||||||
|
"Valore": "344"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328243,
|
||||||
|
"Valore": "1208"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328244,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328245,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328246,
|
||||||
|
"Valore": "Not provided"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328247,
|
||||||
|
"Valore": "AAA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328254,
|
||||||
|
"Valore": "aaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328255,
|
||||||
|
"Valore": "4678"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328256,
|
||||||
|
"Valore": "Leather&amp;Fur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328257,
|
||||||
|
"Valore": "278"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328258,
|
||||||
|
"Valore": "2089"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdCommesseCustomFields": 23328262,
|
||||||
|
"Valore": "745"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
null
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
CAMPIONE #0
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 95833,
|
||||||
|
"Matrice": 8413,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "aaa"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"IdCampione": 14445,
|
||||||
|
"Commessa": 95833,
|
||||||
|
"Matrice": 8413
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
CAMPIONE #1
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/Campione' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Commessa": 95833,
|
||||||
|
"Matrice": 3879,
|
||||||
|
"SottoMatrice": null,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"NoteWeb": "bbb"
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"IdCampione": 15750,
|
||||||
|
"Commessa": 95833,
|
||||||
|
"Matrice": 3879
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
curl --location --request GET 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(95833)?$expand=CommesseCustomFields($expand=CustomField)' \
|
||||||
|
--header 'Authorization: Bearer ••••••'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"IdCommessa": 95833,
|
||||||
|
"CodiceCommessa": "SIM-95833",
|
||||||
|
"CommesseCustomFields": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
curl --location --request GET 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(95833)?$expand=CommesseCustomFields($expand=CustomField)' \
|
||||||
|
--header 'Authorization: Bearer ••••••'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"IdCommessa": 95833,
|
||||||
|
"CodiceCommessa": "SIM-95833",
|
||||||
|
"CommesseCustomFields": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb(95833)/ImportaCommessa' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"simulated": true,
|
||||||
|
"endpoint": "CommessaWeb(95833)\/ImportaCommessa"
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
Photos for CommessaWeb 95833 (iddatadb=1237):
|
||||||
|
Total photos found: 1
|
||||||
|
|
||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/AllegatoCommessaWeb' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--form 'IdCommessa=95833' \
|
||||||
|
--form 'file=@C:\xampp\htdocs\trf_certest\public\photostrf\1237-20260228192737-Blue and White Simple Daily Vlogger YouTube Banner (15) (1) (1).png'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"simulated": true,
|
||||||
|
"file": "1237-20260228192737-Blue and White Simple Daily Vlogger YouTube Banner (15) (1) (1).png"
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb",
|
||||||
|
"ClienteResponsabile": 3,
|
||||||
|
"MoltiplicatorePrezzo": 1,
|
||||||
|
"AnagraficaCertestObject": 2,
|
||||||
|
"AnagraficaCertestService": 1,
|
||||||
|
"ClienteFornitore": null
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"IdCommessa": 95833,
|
||||||
|
"CodiceCommessa": "SIM-95833",
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb",
|
||||||
|
"ClienteResponsabile": 7586,
|
||||||
|
"MoltiplicatorePrezzo": 3,
|
||||||
|
"AnagraficaCertestObject": 8963,
|
||||||
|
"AnagraficaCertestService": 9007,
|
||||||
|
"ClienteFornitore": null
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 562479,
|
||||||
|
"CodiceCommessa": "26C0013",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-06T09:09:16.9338074+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0013",
|
||||||
|
"DataInviatoWeb": null,
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb",
|
||||||
|
"ClienteResponsabile": 10653,
|
||||||
|
"MoltiplicatorePrezzo": 1,
|
||||||
|
"AnagraficaCertestObject": 8960,
|
||||||
|
"AnagraficaCertestService": 9010,
|
||||||
|
"ClienteFornitore": null
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 563528,
|
||||||
|
"CodiceCommessa": "26C0029",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-11T14:10:00.8960358+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0029",
|
||||||
|
"DataInviatoWeb": null,
|
||||||
|
"Richiedente": "Test Web Import",
|
||||||
|
"Descrizione": "TEST CommessaWeb"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application",
|
||||||
|
"ClienteResponsabile": 7598,
|
||||||
|
"MoltiplicatorePrezzo": 2,
|
||||||
|
"AnagraficaCertestObject": 8964,
|
||||||
|
"AnagraficaCertestService": 9012,
|
||||||
|
"ClienteFornitore": 11208
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564662,
|
||||||
|
"CodiceCommessa": "26C0058",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-17T14:49:39.4933462+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0058",
|
||||||
|
"DataInviatoWeb": null,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application",
|
||||||
|
"ClienteResponsabile": 7598,
|
||||||
|
"MoltiplicatorePrezzo": 2,
|
||||||
|
"AnagraficaCertestObject": 8964,
|
||||||
|
"AnagraficaCertestService": 9012,
|
||||||
|
"ClienteFornitore": 11208
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564663,
|
||||||
|
"CodiceCommessa": "26C0059",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-17T14:52:29.3463415+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0059",
|
||||||
|
"DataInviatoWeb": null,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application",
|
||||||
|
"ClienteResponsabile": 7586,
|
||||||
|
"MoltiplicatorePrezzo": null,
|
||||||
|
"AnagraficaCertestObject": 8973,
|
||||||
|
"AnagraficaCertestService": 9007,
|
||||||
|
"ClienteFornitore": 11208
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 564817,
|
||||||
|
"CodiceCommessa": "26C0071",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-18T10:54:02.1867227+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0071",
|
||||||
|
"DataInviatoWeb": null,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
curl --location --request POST 'https://93.43.5.102/limsapi/api/odata/CommessaWeb' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--header 'Authorization: Bearer ••••••' \
|
||||||
|
--data '{
|
||||||
|
"Cliente": 3378,
|
||||||
|
"SchemaCustomField": 82,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application",
|
||||||
|
"ClienteResponsabile": 7586,
|
||||||
|
"MoltiplicatorePrezzo": 2,
|
||||||
|
"AnagraficaCertestObject": 8973,
|
||||||
|
"AnagraficaCertestService": 9007,
|
||||||
|
"ClienteFornitore": 4505,
|
||||||
|
"ClienteAnalisi": null
|
||||||
|
}'
|
||||||
|
|
||||||
|
RESPONSE:
|
||||||
|
{
|
||||||
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#CommessaWeb\/$entity",
|
||||||
|
"IdCommessa": 565085,
|
||||||
|
"CodiceCommessa": "26C0089",
|
||||||
|
"RiferimentoCertificato": null,
|
||||||
|
"StatoCommessaWeb": "Nuova",
|
||||||
|
"DataCreazioneWeb": "2026-03-19T10:03:18.6527414+01:00",
|
||||||
|
"CodiceCommessaWeb": "26C0089",
|
||||||
|
"DataInviatoWeb": null,
|
||||||
|
"Richiedente": "From TRFSmart Application",
|
||||||
|
"Descrizione": "From TRFSmart Application"
|
||||||
|
}
|
||||||
@@ -97,6 +97,31 @@ if (!$template) {
|
|||||||
<ul id="associationsList" class="list-group border p-3"></ul>
|
<ul id="associationsList" class="list-group border p-3"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Default Values (Fixed fields) -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h5>Default Values (Fixed fields)</h5>
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">MoltiplicatorePrezzo (default)</label>
|
||||||
|
<select id="defaultMoltiplicatorePrezzo" class="form-select">
|
||||||
|
<option value="">Loading...</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">Loaded from API: get_moltiplicatoreprezzo.php</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">ConsegnaRichiesta (default)</label>
|
||||||
|
<input type="date" id="defaultConsegnaRichiesta" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<button class="btn btn-success" id="saveDefaultsBtn">💾 Save defaults</button>
|
||||||
|
<span id="defaultsStatus" class="ms-2 text-muted"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Save Button -->
|
<!-- Save Button -->
|
||||||
<div class="mt-4 text-end">
|
<div class="mt-4 text-end">
|
||||||
<a href="templates_dashboard.php" class="btn btn-primary">⬅ Back to Template Dashboard</a>
|
<a href="templates_dashboard.php" class="btn btn-primary">⬅ Back to Template Dashboard</a>
|
||||||
@@ -273,7 +298,7 @@ if (!$template) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error loading table columns:', error));
|
.catch(error => console.error('Error loading table columns:', error));
|
||||||
*/
|
*/
|
||||||
/** =======================
|
/** =======================
|
||||||
* CARICAMENTO MAPPATURE GIÀ ESISTENTI
|
* CARICAMENTO MAPPATURE GIÀ ESISTENTI
|
||||||
* ======================= */
|
* ======================= */
|
||||||
@@ -441,6 +466,97 @@ if (!$template) {
|
|||||||
})
|
})
|
||||||
.catch(error => console.error("❌ Fetch error:", error));
|
.catch(error => console.error("❌ Fetch error:", error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** =======================
|
||||||
|
* DEFAULTS (Fixed fields)
|
||||||
|
* - stored in localStorage for now
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
const defaultsKey = "tpl_defaults_" + templateId;
|
||||||
|
|
||||||
|
function loadDefaultsFromLocal() {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(defaultsKey);
|
||||||
|
if (!raw) return;
|
||||||
|
const saved = JSON.parse(raw);
|
||||||
|
|
||||||
|
if (saved && typeof saved === "object") {
|
||||||
|
if (saved.moltiplicatore_prezzo_id !== undefined) {
|
||||||
|
document.getElementById('defaultMoltiplicatorePrezzo').value = saved.moltiplicatore_prezzo_id || "";
|
||||||
|
}
|
||||||
|
if (saved.consegna_richiesta !== undefined) {
|
||||||
|
document.getElementById('defaultConsegnaRichiesta').value = saved.consegna_richiesta || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("⚠️ Cannot parse saved defaults:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDefaultsToLocal() {
|
||||||
|
const moltiplicatoreId = document.getElementById('defaultMoltiplicatorePrezzo').value || "";
|
||||||
|
const consegna = document.getElementById('defaultConsegnaRichiesta').value || "";
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
moltiplicatore_prezzo_id: moltiplicatoreId,
|
||||||
|
consegna_richiesta: consegna
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorage.setItem(defaultsKey, JSON.stringify(payload));
|
||||||
|
|
||||||
|
const status = document.getElementById('defaultsStatus');
|
||||||
|
status.textContent = "✅ Defaults saved for this template (local)";
|
||||||
|
setTimeout(() => status.textContent = "", 2500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMoltiplicatoriPrezzo() {
|
||||||
|
const select = document.getElementById('defaultMoltiplicatorePrezzo');
|
||||||
|
select.innerHTML = `<option value="">-- Select --</option>`;
|
||||||
|
|
||||||
|
fetch('get_moltiplicatoreprezzo.php')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
// OData tipico: { value: [...] }
|
||||||
|
const rows = Array.isArray(data?.value) ? data.value : (Array.isArray(data) ? data : []);
|
||||||
|
if (!rows.length) {
|
||||||
|
select.innerHTML = `<option value="">(No data)</option>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.forEach(item => {
|
||||||
|
// ⚠️ Qui i nomi campi dipendono dal JSON reale:
|
||||||
|
// - id: item.Id / item.ID / item.idMoltiplicatorePrezzo
|
||||||
|
// - label: item.Descrizione / item.Nome / item.Codice
|
||||||
|
const id = item.IdMoltiplicatorePrezzo;
|
||||||
|
const label = `${item.Descrizione} (x${item.Fattore})`;
|
||||||
|
|
||||||
|
|
||||||
|
if (id === undefined || id === null) return;
|
||||||
|
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = String(id);
|
||||||
|
opt.textContent = String(label);
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
// dopo aver popolato, prova a rimettere il valore salvato
|
||||||
|
loadDefaultsFromLocal();
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error("❌ Error loading MoltiplicatorePrezzo:", err);
|
||||||
|
select.innerHTML = `<option value="">(Load error)</option>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
document.getElementById('saveDefaultsBtn').addEventListener('click', function() {
|
||||||
|
saveDefaultsToLocal();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Init
|
||||||
|
loadMoltiplicatoriPrezzo();
|
||||||
|
loadDefaultsFromLocal();
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,22 @@
|
|||||||
<!-- Modal per la gestione delle annotazioni -->
|
<!-- Modal per la gestione delle annotazioni -->
|
||||||
<div class="modal fade" id="annotationsModal" tabindex="-1" aria-labelledby="annotationsModalLabel" aria-hidden="true">
|
<div class="modal fade" id="annotationsModal" tabindex="-1" aria-labelledby="annotationsModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl" style="max-width: 80% !important; width: 80% !important;">
|
<div class="modal-dialog modal-xl" style="max-width: 90% !important; width: 90% !important;">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="annotationsModalLabel">Annotazioni per TRF: <span id="trfHeaderAnnotations"></span></h5>
|
<h5 class="modal-title" id="annotationsModalLabel">Annotazioni per TRF: <span id="trfHeaderAnnotations"></span></h5>
|
||||||
|
|
||||||
|
<!-- SLIDER PER DIMENSIONE MARKER -->
|
||||||
|
<div style="display: flex; align-items: center; gap: 10px; margin-left: 20px;">
|
||||||
|
<label for="markerSizeSlider" style="margin: 0; font-size: 0.9rem; white-space: nowrap;">Dimensione marker:</label>
|
||||||
|
<input type="range" id="markerSizeSlider" min="16" max="48" value="16" step="2" style="width: 120px;">
|
||||||
|
<span id="markerSizeValue" style="font-weight: bold; min-width: 30px;">24px</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<!-- COLONNA SINISTRA RIDOTTA -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
<h6 style="margin: 0;">Elenco Parti</h6>
|
<h6 style="margin: 0;">Elenco Parti</h6>
|
||||||
@@ -16,15 +25,17 @@
|
|||||||
<label for="showMixPartsAnnotations" style="font-size: 0.9rem;">Mix</label>
|
<label for="showMixPartsAnnotations" style="font-size: 0.9rem;">Mix</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul id="partsListAnnotations" class="list-group"></ul>
|
<ul id="partsListAnnotations" class="list-group" style="max-height: 500px; overflow-y: auto;"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- COLONNA DESTRA PIÙ GRANDE -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6>Foto del Campione</h6>
|
<h6>Foto del Campione</h6>
|
||||||
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
||||||
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
||||||
<div id="photoSelectorContainerAnnotations" style="display: none;"></div>
|
<div id="photoSelectorContainerAnnotations" style="display: none;"></div>
|
||||||
</div>
|
</div>
|
||||||
<div style="position: relative; width: 100%; min-height: 400px;">
|
<div style="position: relative; width: 100%; min-height: 500px; border: 1px solid #ddd; border-radius: 4px; overflow: hidden;">
|
||||||
<img id="samplePhotoAnnotations" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
<img id="samplePhotoAnnotations" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
||||||
<canvas id="photoCanvasAnnotations" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
<canvas id="photoCanvasAnnotations" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
||||||
<canvas id="overlayCanvasAnnotations" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000;"></canvas>
|
<canvas id="overlayCanvasAnnotations" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000;"></canvas>
|
||||||
@@ -216,4 +227,48 @@
|
|||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
z-index: 3000;
|
z-index: 3000;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
/* Stile per lo slider */
|
||||||
|
#markerSizeSlider {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #ddd;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markerSizeSlider::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #007bff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markerSizeSlider::-moz-range-thumb {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #007bff;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .list-group-item.dragging {
|
||||||
|
opacity: 0.6;
|
||||||
|
background-color: #d1e7dd !important;
|
||||||
|
transform: rotate(3deg);
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .placeholder {
|
||||||
|
background-color: #f8d7da !important;
|
||||||
|
border: 2px dashed #dc3545;
|
||||||
|
height: 40px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
|
||||||
@@ -307,4 +307,23 @@
|
|||||||
width: 250px !important;
|
width: 250px !important;
|
||||||
min-width: 250px !important;
|
min-width: 250px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#partsTableBody .extra-field-td .select2-container {
|
||||||
|
width: 100% !important;
|
||||||
|
min-width: 180px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTableBody .extra-field-td .select2-selection--single {
|
||||||
|
height: 31px !important;
|
||||||
|
padding: 0.15rem 0.35rem !important;
|
||||||
|
border: 1px solid #ced4da !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTableBody .extra-field-td .select2-selection__rendered {
|
||||||
|
line-height: 28px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTableBody .extra-field-td .select2-selection__arrow {
|
||||||
|
height: 29px !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true">
|
<div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl" style="max-width: 80% !important;">
|
<div class="modal-dialog modal-xl" style="max-width: 95vw !important;">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="partsModalLabel">Parti per TRF: <span id="trfHeader"></span></h5>
|
<h5 class="modal-title" id="partsModalLabel">Parti per TRF: <span id="trfHeader"></span></h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="row">
|
<div class="row parts-row">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
@@ -14,6 +14,11 @@
|
|||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center;">
|
||||||
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rinumera Parti</button>
|
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rinumera Parti</button>
|
||||||
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-microphone"></i> Voce</button>
|
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-microphone"></i> Voce</button>
|
||||||
|
<button type="button" class="btn btn-info btn-sm ms-2 d-none" id="quotationeBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Add Quotation</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm ms-2" id="showHideImageBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
|
<i class="fas fa-eye-slash" style="font-size: 0.8rem;"></i>
|
||||||
|
<i class="fas fa-image ms-1" style="font-size: 0.8rem;"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Seconda riga: +, M, MacroMatrice, Matrice globale, Propaga -->
|
<!-- Seconda riga: +, M, MacroMatrice, Matrice globale, Propaga -->
|
||||||
@@ -29,7 +34,7 @@
|
|||||||
<table class="table table-striped table-sm" id="partsTable">
|
<table class="table table-striped table-sm" id="partsTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 80px;">Numero</th>
|
<th style="width: 55px;">Num</th>
|
||||||
<th>Descrizione</th>
|
<th>Descrizione</th>
|
||||||
<th style="width: 200px;">Matrice</th>
|
<th style="width: 200px;">Matrice</th>
|
||||||
<th style="width: 150px;">
|
<th style="width: 150px;">
|
||||||
@@ -46,7 +51,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody id="partsTableBody">
|
<tbody id="partsTableBody">
|
||||||
<tr data-part-id="new">
|
<tr data-part-id="new">
|
||||||
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
|
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 55px;"></td>
|
||||||
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione"></td>
|
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione"></td>
|
||||||
<td>
|
<td>
|
||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center;">
|
||||||
@@ -141,6 +146,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Finestra modale "Aggiungi preventivo" -->
|
||||||
|
<div class="modal fade" id="addQuotationModal" tabindex="-1" aria-labelledby="addQuotationModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-md">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="addQuotationModalLabel">Choose a quotation</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<select id="addQuotationSelect" class="form-control form-control-sm" style="width: 100% !important; min-width: 100% !important"></select>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="addQuotationBtn">Confirm</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* --- Base --- */
|
/* --- Base --- */
|
||||||
@@ -157,6 +180,14 @@
|
|||||||
max-width: 100% !important
|
max-width: 100% !important
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#addQuotationModal {
|
||||||
|
z-index: 1060 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#addQuotationModal .modal-backdrop {
|
||||||
|
z-index: 1055 !important
|
||||||
|
}
|
||||||
|
|
||||||
/* Tabelle */
|
/* Tabelle */
|
||||||
#partsTable tr {
|
#partsTable tr {
|
||||||
display: table-row !important
|
display: table-row !important
|
||||||
@@ -256,9 +287,13 @@
|
|||||||
/* Colonna Descrizione (2ª colonna) = 420px */
|
/* Colonna Descrizione (2ª colonna) = 420px */
|
||||||
#partsTable th:nth-child(2),
|
#partsTable th:nth-child(2),
|
||||||
#partsTable td:nth-child(2) {
|
#partsTable td:nth-child(2) {
|
||||||
width: 350 !important;
|
width: 300px !important;
|
||||||
min-width: 350px !important;
|
min-width: 300px !important;
|
||||||
max-width: 350px !important;
|
max-width: 300px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable .part-number {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#partsTable td:nth-child(2) .part-description {
|
#partsTable td:nth-child(2) .part-description {
|
||||||
|
|||||||
+449
-21
@@ -6,6 +6,9 @@ $(document).ready(function () {
|
|||||||
let unsavedChanges = false;
|
let unsavedChanges = false;
|
||||||
let matrici = [];
|
let matrici = [];
|
||||||
let macroMatrici = [];
|
let macroMatrici = [];
|
||||||
|
let quotations = [];
|
||||||
|
let partsExtraField = null; // {field_id, field_label} oppure null
|
||||||
|
let extraFieldOptions = []; // [{id,label}]
|
||||||
|
|
||||||
// --- ROW ID helpers: niente più cache impazzita di jQuery .data() ---
|
// --- ROW ID helpers: niente più cache impazzita di jQuery .data() ---
|
||||||
function getPartId($row) {
|
function getPartId($row) {
|
||||||
@@ -28,6 +31,202 @@ $(document).ready(function () {
|
|||||||
return id === "new" || id === "" || id === null ? null : id;
|
return id === "new" || id === "" || id === null ? null : id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadPartsExtraField(iddatadb, done) {
|
||||||
|
partsExtraField = null;
|
||||||
|
|
||||||
|
if (!iddatadb) return done();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "get_parts_extra_field.php",
|
||||||
|
method: "GET",
|
||||||
|
dataType: "json",
|
||||||
|
data: { iddatadb },
|
||||||
|
success: function (res) {
|
||||||
|
partsExtraField =
|
||||||
|
res && res.success && res.field ? res.field : null;
|
||||||
|
|
||||||
|
if (
|
||||||
|
partsExtraField &&
|
||||||
|
(partsExtraField.data_type || "").toLowerCase() ===
|
||||||
|
"sceltamultipla"
|
||||||
|
) {
|
||||||
|
loadExtraFieldOptions(
|
||||||
|
String(partsExtraField.field_id),
|
||||||
|
function () {
|
||||||
|
applyExtraFieldColumn();
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
applyExtraFieldColumn();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
partsExtraField = null;
|
||||||
|
applyExtraFieldColumn();
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadExtraFieldOptions(fieldId, done) {
|
||||||
|
extraFieldOptions = [];
|
||||||
|
if (!fieldId) return done();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "get_customfield_values.php",
|
||||||
|
method: "GET",
|
||||||
|
dataType: "json",
|
||||||
|
data: { field_ids: fieldId },
|
||||||
|
success: function (res) {
|
||||||
|
const arr = res && res[fieldId] ? res[fieldId] : [];
|
||||||
|
|
||||||
|
extraFieldOptions = (arr || [])
|
||||||
|
.map((x) => ({
|
||||||
|
id: x.IdCustomFieldsValue,
|
||||||
|
label: x.Valore || "",
|
||||||
|
}))
|
||||||
|
.sort((a, b) =>
|
||||||
|
a.label.localeCompare(b.label, "it", {
|
||||||
|
sensitivity: "base",
|
||||||
|
numeric: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
extraFieldOptions = [];
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildExtraFieldCellHtml($row = null) {
|
||||||
|
if (!partsExtraField) return "";
|
||||||
|
|
||||||
|
const selectedValueId = $row ? $row.data("extra-value-id") || "" : "";
|
||||||
|
|
||||||
|
// SceltaMultipla -> select + hidden value id
|
||||||
|
if (
|
||||||
|
(partsExtraField.data_type || "").toLowerCase() === "sceltamultipla"
|
||||||
|
) {
|
||||||
|
const opts = [`<option value="">Select…</option>`]
|
||||||
|
.concat(
|
||||||
|
extraFieldOptions.map(
|
||||||
|
(o) => `<option value="${o.id}">${o.label}</option>`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
return `
|
||||||
|
<td class="extra-field-td" style="width:200px;">
|
||||||
|
<input type="hidden" class="part-extra-field-id" value="${partsExtraField.field_id}">
|
||||||
|
<input type="hidden" class="part-extra-value-id" value="">
|
||||||
|
<select class="form-control form-control-sm part-extra-select" data-selected="${selectedValueId || ""}">${opts}</select>
|
||||||
|
</td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Testo -> input + hidden field_id
|
||||||
|
return `
|
||||||
|
<td class="extra-field-td" style="width:200px;">
|
||||||
|
<input type="hidden" class="part-extra-field-id" value="${partsExtraField.field_id}">
|
||||||
|
<input type="text" class="form-control form-control-sm part-extra-field" data-type="${partsExtraField.data_type || ""}">
|
||||||
|
</td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeExtraFieldSelect2($context) {
|
||||||
|
if (typeof $.fn.select2 === "undefined") return;
|
||||||
|
|
||||||
|
$context.find(".part-extra-select").each(function () {
|
||||||
|
const $select = $(this);
|
||||||
|
|
||||||
|
if ($select.hasClass("select2-hidden-accessible")) {
|
||||||
|
$select.select2("destroy");
|
||||||
|
}
|
||||||
|
|
||||||
|
$select.select2({
|
||||||
|
placeholder: "Seleziona...",
|
||||||
|
allowClear: true,
|
||||||
|
width: "100%",
|
||||||
|
dropdownParent: $("#partsModal"),
|
||||||
|
minimumResultsForSearch: 0,
|
||||||
|
sorter: function (data) {
|
||||||
|
return data.sort(function (a, b) {
|
||||||
|
const textA = (a.text || "").toLowerCase();
|
||||||
|
const textB = (b.text || "").toLowerCase();
|
||||||
|
return textA.localeCompare(textB, "it", {
|
||||||
|
sensitivity: "base",
|
||||||
|
numeric: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
matcher: function (params, data) {
|
||||||
|
if ($.trim(params.term) === "") return data;
|
||||||
|
if (typeof data.text === "undefined") return null;
|
||||||
|
|
||||||
|
const term = params.term.toLowerCase();
|
||||||
|
const text = data.text.toLowerCase();
|
||||||
|
|
||||||
|
return text.indexOf(term) > -1 ? data : null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const selected = ($select.attr("data-selected") || "").toString();
|
||||||
|
if (selected) {
|
||||||
|
$select.val(selected).trigger("change.select2");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("change", ".part-extra-select", function () {
|
||||||
|
const valId = $(this).val() || "";
|
||||||
|
const $row = $(this).closest("tr");
|
||||||
|
|
||||||
|
// salva nello stato della riga (così sopravvive ai re-render)
|
||||||
|
$row.data("extra-value-id", valId);
|
||||||
|
|
||||||
|
$(this).closest("td").find(".part-extra-value-id").val(valId);
|
||||||
|
saveRow($row);
|
||||||
|
});
|
||||||
|
|
||||||
|
function applyExtraFieldColumn() {
|
||||||
|
const $theadRow = $("#partsTable thead tr");
|
||||||
|
|
||||||
|
// 1) rimuovi header extra
|
||||||
|
$theadRow.find("th.extra-field-th").remove();
|
||||||
|
|
||||||
|
// 2) rimuovi celle extra esistenti
|
||||||
|
$("#partsTableBody tr").each(function () {
|
||||||
|
$(this).find("td.extra-field-td").remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3) se non c'è campo extra -> fine
|
||||||
|
if (!partsExtraField) return;
|
||||||
|
|
||||||
|
// 4) inserisci header prima di "Azioni" (ultima colonna)
|
||||||
|
$theadRow
|
||||||
|
.find("th:last")
|
||||||
|
.before(
|
||||||
|
`<th class="extra-field-th" style="width:200px;">${partsExtraField.field_label}</th>`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5) aggiungi cella a ogni riga già presente (una sola volta)
|
||||||
|
$("#partsTableBody tr").each(function () {
|
||||||
|
const $row = $(this);
|
||||||
|
$row.find("td:last").before(buildExtraFieldCellHtml($row));
|
||||||
|
|
||||||
|
const selected = ($row.data("extra-value-id") || "").toString();
|
||||||
|
if (selected) {
|
||||||
|
$row.find(".part-extra-value-id").val(selected);
|
||||||
|
$row.find(".part-extra-select").attr("data-selected", selected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
initializeExtraFieldSelect2($("#partsTableBody"));
|
||||||
|
}
|
||||||
|
|
||||||
function setPartId($row, id) {
|
function setPartId($row, id) {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
// Sincronizza TUTTO: attributo + cache jQuery + nostra cache
|
// Sincronizza TUTTO: attributo + cache jQuery + nostra cache
|
||||||
@@ -141,7 +340,7 @@ $(document).ready(function () {
|
|||||||
// ===================
|
// ===================
|
||||||
// MODAL HANDLING
|
// MODAL HANDLING
|
||||||
// ===================
|
// ===================
|
||||||
function loadParts(iddatadb, idquotations) {
|
function loadParts(iddatadb, idquotations, callback = null) {
|
||||||
if (iddatadb) {
|
if (iddatadb) {
|
||||||
if (matrici.length === 0) {
|
if (matrici.length === 0) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -152,15 +351,19 @@ $(document).ready(function () {
|
|||||||
matrici = data.value || [];
|
matrici = data.value || [];
|
||||||
loadMacroMatrici();
|
loadMacroMatrici();
|
||||||
initializeGlobalSelect2();
|
initializeGlobalSelect2();
|
||||||
loadPhoto(iddatadb, idquotations);
|
loadPartsExtraField(iddatadb, function () {
|
||||||
loadExistingParts(iddatadb, idquotations);
|
loadPhoto(iddatadb, idquotations);
|
||||||
|
loadExistingParts(iddatadb, idquotations, callback);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
matrici = [];
|
matrici = [];
|
||||||
loadMacroMatrici();
|
loadMacroMatrici();
|
||||||
initializeGlobalSelect2();
|
initializeGlobalSelect2();
|
||||||
loadPhoto(iddatadb, idquotations);
|
loadPartsExtraField(iddatadb, function () {
|
||||||
loadExistingParts(iddatadb, idquotations);
|
loadPhoto(iddatadb, idquotations);
|
||||||
|
loadExistingParts(iddatadb, idquotations, callback);
|
||||||
|
});
|
||||||
const errorMsg = $(
|
const errorMsg = $(
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Errore nel caricamento delle matrici: ' +
|
'<div class="alert alert-danger temp-alert" role="alert">Errore nel caricamento delle matrici: ' +
|
||||||
error +
|
error +
|
||||||
@@ -179,12 +382,16 @@ $(document).ready(function () {
|
|||||||
} else {
|
} else {
|
||||||
loadMacroMatrici();
|
loadMacroMatrici();
|
||||||
initializeGlobalSelect2();
|
initializeGlobalSelect2();
|
||||||
loadPhoto(iddatadb, idquotations);
|
loadPartsExtraField(iddatadb, function () {
|
||||||
loadExistingParts(iddatadb, idquotations);
|
loadPhoto(iddatadb, idquotations);
|
||||||
|
loadExistingParts(iddatadb, idquotations, callback);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loadPhoto(iddatadb, idquotations);
|
loadPartsExtraField(iddatadb, function () {
|
||||||
loadExistingParts(iddatadb, idquotations);
|
loadPhoto(iddatadb, idquotations);
|
||||||
|
loadExistingParts(iddatadb, idquotations, callback);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,6 +720,11 @@ $(document).ready(function () {
|
|||||||
if (response.new_id) return response.new_id;
|
if (response.new_id) return response.new_id;
|
||||||
if (response.partId) return response.partId;
|
if (response.partId) return response.partId;
|
||||||
|
|
||||||
|
// ✅ RISPOSTA DI save_parts.php: { success:true, results:[{part_id:...}] }
|
||||||
|
if (Array.isArray(response.results) && response.results[0]) {
|
||||||
|
if (response.results[0].part_id) return response.results[0].part_id;
|
||||||
|
if (response.results[0].id) return response.results[0].id;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,6 +738,13 @@ $(document).ready(function () {
|
|||||||
const iddatadb = $("#partsModal").data("iddatadb");
|
const iddatadb = $("#partsModal").data("iddatadb");
|
||||||
const idquotations = $("#partsModal").data("idquotations");
|
const idquotations = $("#partsModal").data("idquotations");
|
||||||
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
|
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
|
||||||
|
|
||||||
|
// EXTRA FIELD (0/1)
|
||||||
|
const extra_field_id = $row.find(".part-extra-field-id").val() || null;
|
||||||
|
const extra_value_id = $row.find(".part-extra-value-id").val() || null;
|
||||||
|
const extra_value_text = $row.find(".part-extra-field").length
|
||||||
|
? ($row.find(".part-extra-field").val() || "").trim()
|
||||||
|
: null;
|
||||||
let partId = getPartId($row);
|
let partId = getPartId($row);
|
||||||
if (partId === "new") partId = null; // difesa extra (non dovrebbe più servire, ma sicura)
|
if (partId === "new") partId = null; // difesa extra (non dovrebbe più servire, ma sicura)
|
||||||
const endpoint = idquotations
|
const endpoint = idquotations
|
||||||
@@ -558,8 +777,14 @@ $(document).ready(function () {
|
|||||||
part_number: partNumber,
|
part_number: partNumber,
|
||||||
part_description: partDescription,
|
part_description: partDescription,
|
||||||
mix: isMix,
|
mix: isMix,
|
||||||
|
idmatrice: $row.find(".part-matrice").val() || null,
|
||||||
dateexpiry: dateexpiry || null,
|
dateexpiry: dateexpiry || null,
|
||||||
note: note,
|
note: note,
|
||||||
|
|
||||||
|
// extra custom field
|
||||||
|
extra_field_id: extra_field_id,
|
||||||
|
extra_value_id: extra_value_id,
|
||||||
|
extra_value_text: extra_value_text,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -589,6 +814,9 @@ $(document).ready(function () {
|
|||||||
if (response.success) {
|
if (response.success) {
|
||||||
$saveStatus.show();
|
$saveStatus.show();
|
||||||
setTimeout(() => $saveStatus.hide(), 2000);
|
setTimeout(() => $saveStatus.hide(), 2000);
|
||||||
|
|
||||||
|
if (!$("#quotationeBtn").hasClass("d-none"))
|
||||||
|
$("#quotationeBtn").addClass("d-none");
|
||||||
} else {
|
} else {
|
||||||
const errorMsg = $(
|
const errorMsg = $(
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio: ' +
|
'<div class="alert alert-danger temp-alert" role="alert">Errore nel salvataggio: ' +
|
||||||
@@ -717,8 +945,9 @@ $(document).ready(function () {
|
|||||||
<select class="part-matrice form-control form-control-sm" style="width: 150px;"></select>
|
<select class="part-matrice form-control form-control-sm" style="width: 150px;"></select>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><input type="date" class="form-control form-control-sm part-dateexpiry" style="width: 130px;"></td>
|
<td><input type="date" class="form-control form-control-sm part-dateexpiry" style="width: 130px;"></td>
|
||||||
<td>
|
${partsExtraField ? buildExtraFieldCellHtml(null) : ``}
|
||||||
|
<td>
|
||||||
<button type="button" class="btn btn-light btn-sm note-btn" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;" title="Aggiungi/Modifica nota"><i class="fas fa-file-alt"></i></button>
|
<button type="button" class="btn btn-light btn-sm note-btn" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;" title="Aggiungi/Modifica nota"><i class="fas fa-file-alt"></i></button>
|
||||||
<button type="button" class="btn btn-warning btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M+</button>
|
<button type="button" class="btn btn-warning btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M+</button>
|
||||||
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
||||||
@@ -727,9 +956,13 @@ $(document).ready(function () {
|
|||||||
</td>
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
$("#partsTableBody").append(newRow);
|
$("#partsTableBody").append(newRow);
|
||||||
const $select = $("#partsTableBody tr:last .part-matrice");
|
const $newRow = $("#partsTableBody tr:last");
|
||||||
|
const $select = $newRow.find(".part-matrice");
|
||||||
const selectedMacro = $("#macro-matrice-filter").val() || "";
|
const selectedMacro = $("#macro-matrice-filter").val() || "";
|
||||||
|
|
||||||
initializeSelect2($select, nextPartNumber, "", null, selectedMacro);
|
initializeSelect2($select, nextPartNumber, "", null, selectedMacro);
|
||||||
|
initializeExtraFieldSelect2($newRow);
|
||||||
|
|
||||||
updateRowButtons();
|
updateRowButtons();
|
||||||
markUnsaved();
|
markUnsaved();
|
||||||
}
|
}
|
||||||
@@ -1151,11 +1384,15 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("blur", ".part-description, .part-number", function () {
|
$(document).on(
|
||||||
saveRow($(this).closest("tr"));
|
"blur",
|
||||||
});
|
".part-description, .part-number, .part-extra-field",
|
||||||
|
function () {
|
||||||
|
saveRow($(this).closest("tr"));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
function loadExistingParts(iddatadb, idquotations) {
|
function loadExistingParts(iddatadb, idquotations, callback = null) {
|
||||||
const endpoint = idquotations
|
const endpoint = idquotations
|
||||||
? "load_parts_quotation.php"
|
? "load_parts_quotation.php"
|
||||||
: "load_parts.php";
|
: "load_parts.php";
|
||||||
@@ -1205,8 +1442,9 @@ $(document).ready(function () {
|
|||||||
<select class="part-matrice form-control form-control-sm" style="width: 150px;" ${idquotations && !part.idmatrice ? "disabled" : ""}></select>
|
<select class="part-matrice form-control form-control-sm" style="width: 150px;" ${idquotations && !part.idmatrice ? "disabled" : ""}></select>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><input type="date" class="form-control form-control-sm part-dateexpiry" value="${part.dateexpiry || ""}" style="width: 130px;"></td>
|
<td><input type="date" class="form-control form-control-sm part-dateexpiry" value="${part.dateexpiry || ""}" style="width: 130px;"></td>
|
||||||
<td>
|
${partsExtraField ? buildExtraFieldCellHtml() : ``}
|
||||||
|
<td>
|
||||||
<button type="button" class="btn btn-light btn-sm note-btn ${part.note ? "has-note" : ""}" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;" title="Aggiungi/Modifica nota"><i class="fas fa-file-alt"></i></button>
|
<button type="button" class="btn btn-light btn-sm note-btn ${part.note ? "has-note" : ""}" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;" title="Aggiungi/Modifica nota"><i class="fas fa-file-alt"></i></button>
|
||||||
<button type="button" class="btn btn-warning btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M+</button>
|
<button type="button" class="btn btn-warning btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M+</button>
|
||||||
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-trash fa-xs"></i></button>
|
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-trash fa-xs"></i></button>
|
||||||
@@ -1215,6 +1453,26 @@ $(document).ready(function () {
|
|||||||
</td>
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
$("#partsTableBody").append(newRow);
|
$("#partsTableBody").append(newRow);
|
||||||
|
|
||||||
|
const $row = $(
|
||||||
|
`#partsTableBody tr[data-part-id="${part.id}"]`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
part.extra_value_id !== undefined &&
|
||||||
|
part.extra_value_id !== null
|
||||||
|
) {
|
||||||
|
const vid = String(part.extra_value_id);
|
||||||
|
$row.data("extra-value-id", vid);
|
||||||
|
$row.find(".part-extra-value-id").val(vid);
|
||||||
|
$row.find(".part-extra-select").attr(
|
||||||
|
"data-selected",
|
||||||
|
vid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeExtraFieldSelect2($row);
|
||||||
|
|
||||||
const $select = $("#partsTableBody").find(
|
const $select = $("#partsTableBody").find(
|
||||||
`tr[data-part-id="${part.id}"] .part-matrice`,
|
`tr[data-part-id="${part.id}"] .part-matrice`,
|
||||||
);
|
);
|
||||||
@@ -1233,8 +1491,11 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
addNewRow(1, false); // Riga iniziale normale
|
addNewRow(1, false); // Riga iniziale normale
|
||||||
|
$("#quotationeBtn").removeClass("d-none");
|
||||||
}
|
}
|
||||||
updateRowButtons();
|
updateRowButtons();
|
||||||
|
|
||||||
|
if (callback) callback();
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
const errorMsg = $(
|
const errorMsg = $(
|
||||||
@@ -1339,6 +1600,7 @@ $(document).ready(function () {
|
|||||||
partId,
|
partId,
|
||||||
currentValue,
|
currentValue,
|
||||||
selectedMacro,
|
selectedMacro,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1415,6 +1677,7 @@ $(document).ready(function () {
|
|||||||
partId,
|
partId,
|
||||||
idmatrice,
|
idmatrice,
|
||||||
selectedMacro = null,
|
selectedMacro = null,
|
||||||
|
fromFilter = false,
|
||||||
) {
|
) {
|
||||||
if (typeof $.fn.select2 === "undefined") {
|
if (typeof $.fn.select2 === "undefined") {
|
||||||
$select.replaceWith(
|
$select.replaceWith(
|
||||||
@@ -1484,16 +1747,24 @@ $(document).ready(function () {
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
$select.append(option).trigger("change");
|
|
||||||
|
if (!fromFilter) $select.append(option).trigger("change");
|
||||||
|
else $select.append(option);
|
||||||
|
|
||||||
partMatrice[partNumber] = matrice.IdMatrice;
|
partMatrice[partNumber] = matrice.IdMatrice;
|
||||||
} else {
|
} else {
|
||||||
// Aggiusta valore non valido
|
// Aggiusta valore non valido
|
||||||
$select.val(null).trigger("change");
|
if (!fromFilter) $select.val(null).trigger("change");
|
||||||
|
|
||||||
partMatrice[partNumber] = null;
|
partMatrice[partNumber] = null;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$select.val(null).trigger("change", [{ skipHandler: true }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$select.on("change", function () {
|
$select.on("change", function (event, data) {
|
||||||
|
if (data && data?.skipHandler) return;
|
||||||
|
|
||||||
const idmatrice = $(this).val();
|
const idmatrice = $(this).val();
|
||||||
const $row = $(this).closest("tr");
|
const $row = $(this).closest("tr");
|
||||||
const partId = $row.data("part-id");
|
const partId = $row.data("part-id");
|
||||||
@@ -1777,6 +2048,141 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
// Esporta la funzione loadParts per essere usata da import_Edit2.php
|
// Esporta la funzione loadParts per essere usata da import_Edit2.php
|
||||||
window.loadParts = loadParts;
|
window.loadParts = loadParts;
|
||||||
|
|
||||||
|
$(document).on("click", "#quotationeBtn", function () {
|
||||||
|
$("#addQuotationModal").modal("show");
|
||||||
|
|
||||||
|
if (quotations.length > 0) {
|
||||||
|
reloadQuotations();
|
||||||
|
} else {
|
||||||
|
$.ajax({
|
||||||
|
url: "load_quotations.php",
|
||||||
|
method: "GET",
|
||||||
|
success: function (response) {
|
||||||
|
quotations = response?.quotations || [];
|
||||||
|
|
||||||
|
reloadQuotations();
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
console.error(
|
||||||
|
"Errore AJAX caricamento quotations:",
|
||||||
|
error,
|
||||||
|
xhr.responseText,
|
||||||
|
);
|
||||||
|
let message = `
|
||||||
|
<div class="alert alert-danger temp-alert" role="alert">
|
||||||
|
Errore nel caricamento delle quotations: ${error} (${xhr.status})
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
$("#partsModal .modal-body").prepend(errorMsg);
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
message.fadeOut(500, function () {
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", "#addQuotationBtn", function () {
|
||||||
|
const quotationId = $("#addQuotationSelect").val();
|
||||||
|
|
||||||
|
if (
|
||||||
|
quotationId &&
|
||||||
|
confirm("Confermo di collegare la quotazione al campione?")
|
||||||
|
) {
|
||||||
|
$("#addQuotationModal").modal("hide");
|
||||||
|
|
||||||
|
loadParts(null, quotationId, () => {
|
||||||
|
$("#quotationeBtn").addClass("d-none");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
$("#partsTableBody tr").each(function () {
|
||||||
|
$(this).find(".save-loading").show();
|
||||||
|
});
|
||||||
|
|
||||||
|
let photoList = $("#photoSelector option")
|
||||||
|
.map(function () {
|
||||||
|
return this.value?.split("/")?.pop();
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
if (!photoList.length) {
|
||||||
|
let path = $("#samplePhoto")
|
||||||
|
.attr("src")
|
||||||
|
?.split("/")
|
||||||
|
?.pop();
|
||||||
|
|
||||||
|
if (path) photoList = [path];
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "save_parts_photo_iddatadb.php",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
iddatadb: $("#partsModal").data("iddatadb"),
|
||||||
|
photoList,
|
||||||
|
partIds: $("#partsTableBody tr")
|
||||||
|
.map(function () {
|
||||||
|
return $(this).data("part-id");
|
||||||
|
})
|
||||||
|
.get(),
|
||||||
|
}),
|
||||||
|
success: function () {
|
||||||
|
$("#partsTableBody tr").each(function () {
|
||||||
|
let $row = $(this);
|
||||||
|
let $saveStatus = $row.find(".save-status");
|
||||||
|
let $saveLoading = $row.find(".save-loading");
|
||||||
|
|
||||||
|
$saveLoading.hide();
|
||||||
|
$saveStatus.show();
|
||||||
|
|
||||||
|
setTimeout(() => $saveStatus.hide(), 2000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
let message = `
|
||||||
|
<div class="alert alert-danger temp-alert" role="alert">
|
||||||
|
Errore di salvataggio: ${error} (${xhr.status})
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
$("#partsModal .modal-body").prepend(message);
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
message.fadeOut(500, function () {
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function reloadQuotations() {
|
||||||
|
if (quotations.length > 0) {
|
||||||
|
$("#addQuotationSelect").empty();
|
||||||
|
|
||||||
|
$("#addQuotationSelect").append(
|
||||||
|
"<option value=''>Seleziona Quotation</option>",
|
||||||
|
);
|
||||||
|
|
||||||
|
quotations.forEach((quotation) => {
|
||||||
|
if (quotation?.description) {
|
||||||
|
$("#addQuotationSelect").append(
|
||||||
|
`<option value='${quotation?.id}'>${quotation?.description}</option>`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#addQuotationSelect").select2();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("change", ".propagate-date-input", function () {
|
$(document).on("change", ".propagate-date-input", function () {
|
||||||
@@ -2000,3 +2406,25 @@ $(document).on("click", ".save-common-note-btn", function () {
|
|||||||
markUnsaved();
|
markUnsaved();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on("click", "#showHideImageBtn", function () {
|
||||||
|
let mainRow = $(this).closest(".parts-row");
|
||||||
|
let photoContainer = mainRow.find(".col-md-3");
|
||||||
|
let tableContainer = mainRow
|
||||||
|
.find("#partsTable")
|
||||||
|
.closest("div[class*='col-md']");
|
||||||
|
|
||||||
|
if (photoContainer.hasClass("d-none")) {
|
||||||
|
photoContainer.removeClass("d-none");
|
||||||
|
tableContainer.removeClass("col-md-12").addClass("col-md-9");
|
||||||
|
$(this).html(
|
||||||
|
"<i class='fas fa-eye-slash' style='font-size: 0.8rem;'></i><i class='fas fa-image ms-1' style='font-size: 0.8rem;'></i>",
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
photoContainer.addClass("d-none");
|
||||||
|
tableContainer.removeClass("col-md-9").addClass("col-md-12");
|
||||||
|
$(this).html(
|
||||||
|
"<i class='fas fa-eye' style='font-size: 0.8rem;'></i><i class='fas fa-image ms-1' style='font-size: 0.8rem;'></i>",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
+161
-3
@@ -349,6 +349,69 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll(".photo-flag-checkbox")
|
||||||
|
.forEach((checkbox) => {
|
||||||
|
checkbox.addEventListener("change", async function () {
|
||||||
|
const photoId = this.getAttribute("data-photo-id");
|
||||||
|
const field = this.getAttribute("data-field");
|
||||||
|
const value = this.checked ? 1 : 0;
|
||||||
|
const currentCheckbox = this;
|
||||||
|
|
||||||
|
// Only one PrimaPagina visually in the current popup
|
||||||
|
if (field === "PrimaPagina" && value === 1) {
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
".photo-flag-checkbox[data-field='PrimaPagina']",
|
||||||
|
)
|
||||||
|
.forEach((cb) => {
|
||||||
|
if (cb !== currentCheckbox) {
|
||||||
|
cb.checked = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const formData = new URLSearchParams();
|
||||||
|
formData.append("photo_id", photoId);
|
||||||
|
formData.append("field", field);
|
||||||
|
formData.append("value", value);
|
||||||
|
|
||||||
|
const response = await fetch("update_photo_flags.php", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type":
|
||||||
|
"application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: formData.toString(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(
|
||||||
|
result.message || "Errore salvataggio flag",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety refresh for PrimaPagina to ensure UI matches DB
|
||||||
|
if (field === "PrimaPagina") {
|
||||||
|
loadPopupContent(iddatadb, idquotations);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert(
|
||||||
|
"Errore durante il salvataggio del flag: " +
|
||||||
|
error.message,
|
||||||
|
);
|
||||||
|
|
||||||
|
// rollback current checkbox
|
||||||
|
currentCheckbox.checked = !currentCheckbox.checked;
|
||||||
|
|
||||||
|
// reload popup to restore coherent state
|
||||||
|
loadPopupContent(iddatadb, idquotations);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
document.querySelectorAll(".thumbnail").forEach((img) => {
|
document.querySelectorAll(".thumbnail").forEach((img) => {
|
||||||
img.addEventListener("click", function () {
|
img.addEventListener("click", function () {
|
||||||
const enlargedImage = document.getElementById("enlargedImage");
|
const enlargedImage = document.getElementById("enlargedImage");
|
||||||
@@ -412,6 +475,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canvas) {
|
||||||
|
canvas.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
canvas = new fabric.Canvas("collageCanvas", {
|
canvas = new fabric.Canvas("collageCanvas", {
|
||||||
backgroundColor: "#fff",
|
backgroundColor: "#fff",
|
||||||
selection: true,
|
selection: true,
|
||||||
@@ -520,6 +588,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
if (isCropping || isRemovingBackground) {
|
if (isCropping || isRemovingBackground) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = JSON.stringify(
|
const state = JSON.stringify(
|
||||||
canvas.toJSON([
|
canvas.toJSON([
|
||||||
"cornerColor",
|
"cornerColor",
|
||||||
@@ -527,12 +596,16 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
"cornerSize",
|
"cornerSize",
|
||||||
"borderColor",
|
"borderColor",
|
||||||
"transparentCorners",
|
"transparentCorners",
|
||||||
|
"backgroundImage",
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
history.push(state);
|
history.push(state);
|
||||||
|
|
||||||
if (history.length > maxHistory) {
|
if (history.length > maxHistory) {
|
||||||
history.shift();
|
history.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,10 +613,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
if (history.length <= 1) {
|
if (history.length <= 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
history.pop();
|
history.pop();
|
||||||
const previousState = history[history.length - 1];
|
const previousState = history[history.length - 1];
|
||||||
|
|
||||||
if (previousState) {
|
if (previousState) {
|
||||||
canvas.clear();
|
|
||||||
canvas.loadFromJSON(previousState, () => {
|
canvas.loadFromJSON(previousState, () => {
|
||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
updateLayersPanel();
|
updateLayersPanel();
|
||||||
@@ -552,8 +626,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
} else {
|
} else {
|
||||||
console.warn("Nessuno stato precedente disponibile");
|
console.warn("Nessuno stato precedente disponibile");
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
canvas.setBackgroundColor("#fff");
|
canvas.backgroundImage = null;
|
||||||
canvas.renderAll();
|
canvas.setBackgroundColor(
|
||||||
|
"#fff",
|
||||||
|
canvas.renderAll.bind(canvas),
|
||||||
|
);
|
||||||
updateLayersPanel();
|
updateLayersPanel();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
@@ -846,6 +923,61 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setCanvasBackground(imgPath) {
|
||||||
|
console.log("setCanvasBackground chiamata con:", imgPath);
|
||||||
|
|
||||||
|
if (!canvas) {
|
||||||
|
console.error("Canvas non inizializzato");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fabric.Image.fromURL(
|
||||||
|
imgPath,
|
||||||
|
(img) => {
|
||||||
|
const canvasWidth = canvas.getWidth();
|
||||||
|
const canvasHeight = canvas.getHeight();
|
||||||
|
|
||||||
|
const imgWidth = img.width;
|
||||||
|
const imgHeight = img.height;
|
||||||
|
|
||||||
|
if (!imgWidth || !imgHeight) {
|
||||||
|
alert(
|
||||||
|
"Impossibile leggere le dimensioni dell'immagine.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale to cover: l'immagine copre tutto il canvas mantenendo il ratio
|
||||||
|
const scale = Math.max(
|
||||||
|
canvasWidth / imgWidth,
|
||||||
|
canvasHeight / imgHeight,
|
||||||
|
);
|
||||||
|
|
||||||
|
img.set({
|
||||||
|
originX: "left",
|
||||||
|
originY: "top",
|
||||||
|
scaleX: scale,
|
||||||
|
scaleY: scale,
|
||||||
|
left: (canvasWidth - imgWidth * scale) / 2,
|
||||||
|
top: (canvasHeight - imgHeight * scale) / 2,
|
||||||
|
selectable: false,
|
||||||
|
evented: false,
|
||||||
|
hasControls: false,
|
||||||
|
hasBorders: false,
|
||||||
|
excludeFromExport: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.setBackgroundImage(img, () => {
|
||||||
|
canvas.requestRenderAll();
|
||||||
|
saveCanvasState();
|
||||||
|
updateLayersPanel();
|
||||||
|
updateButtons();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ crossOrigin: "anonymous" },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const addToCanvasBtn = document.getElementById("addToCanvasBtn");
|
const addToCanvasBtn = document.getElementById("addToCanvasBtn");
|
||||||
if (addToCanvasBtn) {
|
if (addToCanvasBtn) {
|
||||||
addToCanvasBtn.addEventListener("click", () => {
|
addToCanvasBtn.addEventListener("click", () => {
|
||||||
@@ -885,6 +1017,32 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setBackgroundBtn = document.getElementById("setBackgroundBtn");
|
||||||
|
if (setBackgroundBtn) {
|
||||||
|
setBackgroundBtn.addEventListener("click", () => {
|
||||||
|
const checkboxes = document.querySelectorAll(
|
||||||
|
".photo-checkbox:checked",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (checkboxes.length === 0) {
|
||||||
|
alert("Seleziona una foto da usare come sfondo!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkboxes.length > 1) {
|
||||||
|
alert("Seleziona una sola foto per lo sfondo!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imgPath = checkboxes[0].getAttribute("data-path");
|
||||||
|
setCanvasBackground(imgPath);
|
||||||
|
|
||||||
|
checkboxes.forEach((cb) => {
|
||||||
|
cb.checked = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const saveCollageBtn = document.getElementById("saveCollageBtn");
|
const saveCollageBtn = document.getElementById("saveCollageBtn");
|
||||||
if (saveCollageBtn) {
|
if (saveCollageBtn) {
|
||||||
saveCollageBtn.addEventListener("click", async () => {
|
saveCollageBtn.addEventListener("click", async () => {
|
||||||
|
|||||||
@@ -117,12 +117,24 @@ $code = $row[$field] ?? 'Non disponibile';
|
|||||||
|
|
||||||
// Recupera le foto associate alla riga
|
// Recupera le foto associate alla riga
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT id, file_path, file_name, description, uploaded_at FROM {$photoTable} WHERE {$photoParamName} = ? ORDER BY uploaded_at DESC");
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
file_path,
|
||||||
|
file_name,
|
||||||
|
uploaded_at,
|
||||||
|
description,
|
||||||
|
StampaNelRapporto,
|
||||||
|
PrimaPagina
|
||||||
|
FROM {$photoTable}
|
||||||
|
WHERE {$photoParamName} = ?
|
||||||
|
ORDER BY uploaded_at DESC
|
||||||
|
");
|
||||||
$stmt->execute([$paramValue]);
|
$stmt->execute([$paramValue]);
|
||||||
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Errore query foto: " . $e->getMessage());
|
error_log("Errore query foto: " . $e->getMessage());
|
||||||
$photos = []; // Imposta array vuoto in caso di errore
|
$photos = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definisci il percorso base per le foto
|
// Definisci il percorso base per le foto
|
||||||
@@ -134,7 +146,7 @@ $uploadUrl = $iddatadb
|
|||||||
? $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb
|
? $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb
|
||||||
: $baseUrl . "/upload_photos_mobile.php?idquotations=" . $idquotations;
|
: $baseUrl . "/upload_photos_mobile.php?idquotations=" . $idquotations;
|
||||||
|
|
||||||
// Genera il QR code con endroid/qr-code 6.0.6
|
// Genera il QR code con endroid/qr-code
|
||||||
$qrCodeDir = '../photostrf/qrcodes/';
|
$qrCodeDir = '../photostrf/qrcodes/';
|
||||||
if (!is_dir($qrCodeDir)) {
|
if (!is_dir($qrCodeDir)) {
|
||||||
mkdir($qrCodeDir, 0755, true);
|
mkdir($qrCodeDir, 0755, true);
|
||||||
@@ -164,6 +176,7 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<p>Caricamento in corso...</p>
|
<p>Caricamento in corso...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Manage Photos</h3>
|
<h3>Manage Photos</h3>
|
||||||
<p><strong>ID:</strong> <?= htmlspecialchars($id) ?></p>
|
<p><strong>ID:</strong> <?= htmlspecialchars($id) ?></p>
|
||||||
<p><strong>Code:</strong> <?= htmlspecialchars($code) ?></p>
|
<p><strong>Code:</strong> <?= htmlspecialchars($code) ?></p>
|
||||||
@@ -182,6 +195,7 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<p>Drag the photo here or click to select</p>
|
<p>Drag the photo here or click to select</p>
|
||||||
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
|
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Area per la webcam -->
|
<!-- Area per la webcam -->
|
||||||
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
|
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
|
||||||
<p>Webcam Preview</p>
|
<p>Webcam Preview</p>
|
||||||
@@ -194,7 +208,9 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
|
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button>
|
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button>
|
||||||
|
|
||||||
<!-- Elenco delle foto -->
|
<!-- Elenco delle foto -->
|
||||||
<div id="photosList">
|
<div id="photosList">
|
||||||
<?php if (empty($photos)): ?>
|
<?php if (empty($photos)): ?>
|
||||||
@@ -204,25 +220,57 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<?php
|
<?php
|
||||||
$filePath = $photoBasePath . $photo['file_path'];
|
$filePath = $photoBasePath . $photo['file_path'];
|
||||||
$fileExists = file_exists($filePath);
|
$fileExists = file_exists($filePath);
|
||||||
|
$stampaNelRapporto = !empty($photo['StampaNelRapporto']) ? 1 : 0;
|
||||||
|
$primaPagina = !empty($photo['PrimaPagina']) ? 1 : 0;
|
||||||
?>
|
?>
|
||||||
<div class="photo-item" data-photo-id="<?= $photo['id'] ?>" style="display: flex; align-items: center; margin-bottom: 10px; border-bottom: 1px solid #eee; padding-bottom: 10px;">
|
<div class="photo-item" data-photo-id="<?= (int)$photo['id'] ?>">
|
||||||
<div style="flex: 1;">
|
<div class="photo-thumb-area">
|
||||||
<?php if ($fileExists): ?>
|
<?php if ($fileExists): ?>
|
||||||
<img src="../photostrf/<?= htmlspecialchars($photo['file_path']) ?>" alt="<?= htmlspecialchars($photo['file_name']) ?>" class="thumbnail" style="max-width: 100px; max-height: 100px; margin-right: 10px; cursor: pointer;">
|
<img src="../photostrf/<?= htmlspecialchars($photo['file_path']) ?>"
|
||||||
|
alt="<?= htmlspecialchars($photo['file_name']) ?>"
|
||||||
|
class="thumbnail"
|
||||||
|
style="max-width: 100px; max-height: 100px; cursor: pointer;">
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p style="color: red;">[File non trovato]</p>
|
<div class="missing-file-box">[File non trovato]</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<p style="margin: 0;">
|
|
||||||
<strong>Nome:</strong> <?= htmlspecialchars($photo['file_name']) ?><br>
|
|
||||||
<strong>Caricata il:</strong> <?= htmlspecialchars($photo['uploaded_at']) ?><br>
|
|
||||||
<strong>Descrizione:</strong> <?= htmlspecialchars($photo['description'] ?? 'Nessuna descrizione') ?>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="delete-photo-btn" data-photo-id="<?= $photo['id'] ?>" style="background: none; border: none; color: #dc3545; cursor: pointer;">
|
|
||||||
<i class="fas fa-trash"></i>
|
<div class="photo-info-area">
|
||||||
</button>
|
<p class="photo-name">
|
||||||
|
<strong>Name:</strong> <?= htmlspecialchars($photo['file_name']) ?>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="photo-flags">
|
||||||
|
<label class="flag-label">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="photo-flag-checkbox"
|
||||||
|
data-photo-id="<?= (int)$photo['id'] ?>"
|
||||||
|
data-field="StampaNelRapporto"
|
||||||
|
<?= $stampaNelRapporto ? 'checked' : '' ?>>
|
||||||
|
Print in Report
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="flag-label">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="photo-flag-checkbox prima-pagina-checkbox"
|
||||||
|
data-photo-id="<?= (int)$photo['id'] ?>"
|
||||||
|
data-field="PrimaPagina"
|
||||||
|
<?= $primaPagina ? 'checked' : '' ?>>
|
||||||
|
First Page
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="photo-actions-area">
|
||||||
|
<button class="delete-photo-btn" data-photo-id="<?= (int)$photo['id'] ?>" type="button">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<!-- Bottone Crea Collage -->
|
<!-- Bottone Crea Collage -->
|
||||||
<button id="createCollageBtn" style="padding: 10px 20px; background: #ffc107; color: white; border: none; cursor: pointer; margin-top: 20px;">Crea Collage</button>
|
<button id="createCollageBtn" style="padding: 10px 20px; background: #ffc107; color: white; border: none; cursor: pointer; margin-top: 20px;">Crea Collage</button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -250,8 +298,11 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bottone per aggiungere selezionate al canvas -->
|
<!-- Bottoni azioni collage -->
|
||||||
<button id="addToCanvasBtn">Aggiungi Selezionate al Canvas</button>
|
<div style="display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 10px;">
|
||||||
|
<button id="addToCanvasBtn">Aggiungi Selezionate al Canvas</button>
|
||||||
|
<button id="setBackgroundBtn" type="button">Imposta Selezionata come Sfondo</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Canvas per editing -->
|
<!-- Canvas per editing -->
|
||||||
<canvas id="collageCanvas" width="960" height="720" style="border: 1px solid #ccc; margin-top: 20px;"></canvas>
|
<canvas id="collageCanvas" width="960" height="720" style="border: 1px solid #ccc; margin-top: 20px;"></canvas>
|
||||||
@@ -283,6 +334,12 @@ $result->saveToFile($qrCodeFile);
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.photo-item {
|
.photo-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding: 12px 0;
|
||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,6 +347,68 @@ $result->saveToFile($qrCodeFile);
|
|||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.photo-thumb-area {
|
||||||
|
flex: 0 0 110px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-info-area {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-actions-area {
|
||||||
|
flex: 0 0 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-name {
|
||||||
|
margin: 0;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-flags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 18px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flag-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flag-label input[type="checkbox"] {
|
||||||
|
transform: scale(1.1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-photo-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #dc3545;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-photo-btn:hover {
|
||||||
|
color: #b02a37;
|
||||||
|
}
|
||||||
|
|
||||||
|
.missing-file-box {
|
||||||
|
color: red;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
#dropArea.highlight {
|
#dropArea.highlight {
|
||||||
border-color: #28a745;
|
border-color: #28a745;
|
||||||
background-color: #e9ecef;
|
background-color: #e9ecef;
|
||||||
|
|||||||
@@ -11,6 +11,36 @@ session_start();
|
|||||||
require_once '../../vendor/autoload.php';
|
require_once '../../vendor/autoload.php';
|
||||||
require_once __DIR__ . '/class/db-functions.php';
|
require_once __DIR__ . '/class/db-functions.php';
|
||||||
|
|
||||||
|
function findHeaderRow(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, array $expectedHeaders, int $startCol, int $highestColIndex, int $maxRowsToScan = 20): ?int
|
||||||
|
{
|
||||||
|
$normalizedExpected = array_filter(array_map(function ($h) {
|
||||||
|
return strtolower(trim(str_replace(['\\r\\n', '\r\n', "\r\n", "\n", "\r"], ' ', $h)));
|
||||||
|
}, $expectedHeaders));
|
||||||
|
$normalizedExpected = array_values($normalizedExpected);
|
||||||
|
sort($normalizedExpected);
|
||||||
|
|
||||||
|
for ($row = 1; $row <= $maxRowsToScan; $row++) {
|
||||||
|
$rowHeaders = [];
|
||||||
|
for ($col = $startCol; $col <= $highestColIndex; $col++) {
|
||||||
|
$colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
||||||
|
$cell = $worksheet->getCell($colLetter . $row);
|
||||||
|
$val = $cell ? trim((string)$cell->getCalculatedValue()) : '';
|
||||||
|
if ($val !== '') {
|
||||||
|
$rowHeaders[] = strtolower(trim(str_replace(["\r\n", "\n", "\r"], ' ', $val)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$normalizedRow = $rowHeaders;
|
||||||
|
sort($normalizedRow);
|
||||||
|
|
||||||
|
$matches = count(array_intersect($normalizedExpected, $normalizedRow));
|
||||||
|
$threshold = (int) ceil(count($normalizedExpected) * 0.6);
|
||||||
|
if ($matches >= $threshold) {
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'apply_routine' => false];
|
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'apply_routine' => false];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -71,9 +101,35 @@ try {
|
|||||||
$highestColumn = $worksheet->getHighestColumn();
|
$highestColumn = $worksheet->getHighestColumn();
|
||||||
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);
|
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);
|
||||||
|
|
||||||
$startRow = max(1, $header_row);
|
|
||||||
$startColumn = max(1, $start_column);
|
$startColumn = max(1, $start_column);
|
||||||
|
|
||||||
|
// Recupera routine e headers dal template — DEVE essere prima dell'auto-detect
|
||||||
|
$stmt = $pdo->prepare("SELECT idroutine, idclient, xls_headers FROM excel_templates WHERE id = ?");
|
||||||
|
$stmt->execute([$template_id]);
|
||||||
|
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
error_log("=== DEBUG TEMPLATE ===");
|
||||||
|
error_log("template raw: " . print_r($template, true));
|
||||||
|
error_log("xls_headers value: " . var_export($template['xls_headers'] ?? 'KEY NON ESISTE', true));
|
||||||
|
error_log("xls_headers empty check: " . var_export(empty($template['xls_headers']), true));
|
||||||
|
// Auto-detect della riga header se xls_headers è disponibile
|
||||||
|
$detectedHeaderRow = $header_row;
|
||||||
|
if (!empty($template['xls_headers'])) {
|
||||||
|
$expectedHeaders = json_decode($template['xls_headers'], true);
|
||||||
|
if (is_array($expectedHeaders) && !empty($expectedHeaders)) {
|
||||||
|
error_log("Expected headers from DB: " . print_r($expectedHeaders, true));
|
||||||
|
$found = findHeaderRow($worksheet, $expectedHeaders, $startColumn, $highestColumnIndex);
|
||||||
|
error_log("findHeaderRow result: " . var_export($found, true));
|
||||||
|
if ($found !== null) {
|
||||||
|
$detectedHeaderRow = $found;
|
||||||
|
error_log("Header row auto-detected at row: $detectedHeaderRow (was: $header_row)");
|
||||||
|
} else {
|
||||||
|
error_log("Header row auto-detection failed, using provided header_row: $header_row");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$startRow = max(1, $detectedHeaderRow);
|
||||||
|
$header_row = $detectedHeaderRow;
|
||||||
|
|
||||||
// Debug dei parametri
|
// Debug dei parametri
|
||||||
error_log("Processing - template_id: $template_id, startRow: $startRow, startColumn: $startColumn, highestRow: $highestRow, highestColumn: $highestColumn, highestColumnIndex: $highestColumnIndex");
|
error_log("Processing - template_id: $template_id, startRow: $startRow, startColumn: $startColumn, highestRow: $highestRow, highestColumn: $highestColumn, highestColumnIndex: $highestColumnIndex");
|
||||||
|
|
||||||
@@ -94,7 +150,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Estrai i dati a partire dalla riga successiva, includendo excelrow
|
// Estrai i dati a partire dalla riga successiva, includendo excelrow
|
||||||
for ($row = $startRow + 1; $row <= $highestRow; $row++) {
|
for ($row = $header_row + 1; $row <= $highestRow; $row++) {
|
||||||
$rowData = [];
|
$rowData = [];
|
||||||
for ($col = $startColumn; $col <= $highestColumnIndex; $col++) {
|
for ($col = $startColumn; $col <= $highestColumnIndex; $col++) {
|
||||||
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
$columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
||||||
@@ -107,10 +163,7 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera routine dal template
|
|
||||||
$stmt = $pdo->prepare("SELECT idroutine, idclient FROM excel_templates WHERE id = ?");
|
|
||||||
$stmt->execute([$template_id]);
|
|
||||||
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if ($template && $template['idroutine']) {
|
if ($template && $template['idroutine']) {
|
||||||
$stmtRoutine = $pdo->prepare("SELECT idroutine, name, filename, headerrow, instruction FROM routine WHERE idroutine = ?");
|
$stmtRoutine = $pdo->prepare("SELECT idroutine, name, filename, headerrow, instruction FROM routine WHERE idroutine = ?");
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ try {
|
|||||||
throw new Exception("Invalid request method.");
|
throw new Exception("Invalid request method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupera e sanifica i dati
|
// Retrieve and sanitize form data
|
||||||
$name = trim($_POST['name']);
|
$name = trim($_POST['name'] ?? '');
|
||||||
$header_row = intval($_POST['header_row']);
|
$source_type = strtoupper(trim($_POST['source_type'] ?? 'XLS'));
|
||||||
$start_column = trim($_POST['start_column']);
|
$header_row = isset($_POST['header_row']) && $_POST['header_row'] !== '' ? intval($_POST['header_row']) : null;
|
||||||
|
$start_column = trim($_POST['start_column'] ?? '');
|
||||||
$description = trim($_POST['description'] ?? '');
|
$description = trim($_POST['description'] ?? '');
|
||||||
$target_table = trim($_POST['target_table']);
|
$target_table = trim($_POST['target_table'] ?? 'datadb');
|
||||||
$idclient = intval($_POST['client_id'] ?? 0);
|
$idclient = intval($_POST['client_id'] ?? 0);
|
||||||
$clientname = trim($_POST['client_name'] ?? '');
|
$clientname = trim($_POST['client_name'] ?? '');
|
||||||
$idschema = intval($_POST['idschema'] ?? 0);
|
$idschema = intval($_POST['idschema'] ?? 0);
|
||||||
@@ -25,24 +26,61 @@ try {
|
|||||||
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
||||||
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
||||||
|
|
||||||
// Controllo sui campi obbligatori
|
// Normalize source type
|
||||||
if (empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idclient <= 0 || $idschema <= 0) {
|
if (!in_array($source_type, ['XLS', 'API'], true)) {
|
||||||
|
$source_type = 'XLS';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required fields validation
|
||||||
|
if ($name === '' || $target_table === '' || $idclient <= 0 || $idschema <= 0) {
|
||||||
throw new Exception("All fields marked with * are required, including client and schema.");
|
throw new Exception("All fields marked with * are required, including client and schema.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connessione al database
|
// XLS-only validation
|
||||||
|
if ($source_type === 'XLS') {
|
||||||
|
if ($header_row === null || $header_row <= 0 || $start_column === '') {
|
||||||
|
throw new Exception("Header Row and Start Column are required for XLS templates.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API templates do not require XLS coordinates
|
||||||
|
if ($source_type === 'API') {
|
||||||
|
$header_row = null;
|
||||||
|
$start_column = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database connection
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Inserisci il nuovo template
|
// Insert the new template
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
INSERT INTO excel_templates
|
INSERT INTO excel_templates
|
||||||
(name, header_row, start_column, description, target_table, idclient, clientname, idschema, schemaname, idroutine,
|
(
|
||||||
button_size, button_bg_color, button_text_color, button_label, created_at, updated_at)
|
name,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
source_type,
|
||||||
|
header_row,
|
||||||
|
start_column,
|
||||||
|
description,
|
||||||
|
target_table,
|
||||||
|
idclient,
|
||||||
|
clientname,
|
||||||
|
idschema,
|
||||||
|
schemaname,
|
||||||
|
idroutine,
|
||||||
|
button_size,
|
||||||
|
button_bg_color,
|
||||||
|
button_text_color,
|
||||||
|
button_label,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||||
");
|
");
|
||||||
|
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$name,
|
$name,
|
||||||
|
$source_type,
|
||||||
$header_row,
|
$header_row,
|
||||||
$start_column,
|
$start_column,
|
||||||
$description,
|
$description,
|
||||||
|
|||||||
@@ -399,14 +399,18 @@ if (isset($_GET['edit_id'])) {
|
|||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php include('modal_parts.php'); ?>
|
<div id="partsModalContainer"></div>
|
||||||
<?php include('photos_functions.php'); ?>
|
<div id="annotationsModalContainer"></div>
|
||||||
|
<?php include 'photos_functions.php'; ?>
|
||||||
|
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="photos.js"></script>
|
<script src="photos.js"></script>
|
||||||
<script src="parts.js"></script>
|
<script src="annotationsModal.js"></script>
|
||||||
|
<script src="partsTable.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
// Mostra messaggi di stato se presenti
|
// Mostra messaggi di stato se presenti
|
||||||
@@ -423,6 +427,45 @@ if (isset($_GET['edit_id'])) {
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(document).on('click', '.parts-btn', function() {
|
||||||
|
const idquotations = $(this).data('idquotations');
|
||||||
|
$.ajax({
|
||||||
|
url: 'modal_partsTable.php',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
idquotations: idquotations
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
$('#partsModalContainer').html(response);
|
||||||
|
const modalElement = document.getElementById('partsModal');
|
||||||
|
if (!modalElement) return;
|
||||||
|
$("#trfHeader").text(`Quotation #${idquotations}`);
|
||||||
|
$("#partsModal").data("idquotations", idquotations);
|
||||||
|
let modal = bootstrap.Modal.getInstance(modalElement) || new bootstrap.Modal(modalElement, {
|
||||||
|
backdrop: true
|
||||||
|
});
|
||||||
|
modal.show();
|
||||||
|
if (typeof window.loadParts === 'function') window.loadParts(null, idquotations);
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
alert('Errore nel caricamento del modale: ' + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('hidden.bs.modal', '#partsModal', function() {
|
||||||
|
$('#partsModalContainer').empty();
|
||||||
|
$('.modal-backdrop').remove();
|
||||||
|
$('body').removeClass('modal-open').css('padding-right', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('hidden.bs.modal', '#annotationsModal', function() {
|
||||||
|
$('#annotationsModalContainer').empty();
|
||||||
|
$('.modal-backdrop').remove();
|
||||||
|
$('body').removeClass('modal-open').css('padding-right', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Inizializza DataTables se non siamo in modalità modifica
|
// Inizializza DataTables se non siamo in modalità modifica
|
||||||
if (!document.querySelector('#editForm')) {
|
if (!document.querySelector('#editForm')) {
|
||||||
$('#quotationsTable').DataTable({
|
$('#quotationsTable').DataTable({
|
||||||
@@ -524,12 +567,7 @@ if (isset($_GET['edit_id'])) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Modale per le foto in quotations.php -->
|
<!-- Modale per le foto in quotations.php -->
|
||||||
<div class="modal" id="photosModal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<span class="close-btn">×</span>
|
|
||||||
<div class="popup-content"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -5,102 +5,211 @@ ini_set('error_log', __DIR__ . '/routine_debug.log');
|
|||||||
function applyRoutine(&$excelData, $routineData)
|
function applyRoutine(&$excelData, $routineData)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Log iniziale
|
// Initial log
|
||||||
error_log("Inizio esecuzione routine Moncler: " . date('Y-m-d H:i:s'));
|
error_log("Inizio esecuzione routine Moncler: " . date('Y-m-d H:i:s'));
|
||||||
error_log("Dati routine: " . print_r($routineData, true));
|
error_log("Dati routine: " . print_r($routineData, true));
|
||||||
error_log("Dati excel_data: " . print_r($excelData, true));
|
error_log("Dati excel_data: " . print_r($excelData, true));
|
||||||
|
|
||||||
// Verifica se excelData è vuoto
|
// Check if excelData is empty
|
||||||
if (empty($excelData)) {
|
if (empty($excelData)) {
|
||||||
throw new Exception("excelData è vuoto o non valido.");
|
throw new Exception("excelData è vuoto o non valido.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estrai informazioni dalla routine con valori predefiniti
|
// Extract routine settings with default values
|
||||||
$action1 = trim($routineData['action1'] ?? 'K');
|
$action1 = trim($routineData['action1'] ?? 'K');
|
||||||
$action2 = trim($routineData['action2'] ?? 'STYLE CODE + STYLE DESCRIPTION');
|
$action2 = trim($routineData['action2'] ?? 'STYLE CODE + STYLE DESCRIPTION');
|
||||||
$action3 = trim($routineData['action3'] ?? 'STYLE CODE');
|
$action3 = trim($routineData['action3'] ?? 'STYLE CODE');
|
||||||
$action4 = trim($routineData['action4'] ?? 'STYLE DESCRIPTION');
|
$action4 = trim($routineData['action4'] ?? 'STYLE DESCRIPTION');
|
||||||
$headers = $routineData['xls_headers'] ?? [];
|
$headers = $routineData['xls_headers'] ?? [];
|
||||||
|
|
||||||
|
// Package-related headers
|
||||||
|
$package_header = 'PACKAGE';
|
||||||
|
$other_test_header = 'Other test from Control Matrix';
|
||||||
|
$only_colorfastness_header = 'Only Colorfastness package';
|
||||||
|
$only_chemical_header = 'Only Chemical package';
|
||||||
|
|
||||||
if (empty($headers)) {
|
if (empty($headers)) {
|
||||||
throw new Exception("Nessun header trovato per la routine Moncler.");
|
throw new Exception("Nessun header trovato per la routine Moncler.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If headers arrive as JSON string, decode them
|
||||||
|
if (!is_array($headers) && is_string($headers)) {
|
||||||
|
$decoded_headers = json_decode($headers, true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded_headers)) {
|
||||||
|
$headers = $decoded_headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($headers) || empty($headers)) {
|
||||||
|
throw new Exception("Gli header della routine non sono validi.");
|
||||||
|
}
|
||||||
|
|
||||||
error_log("Header ricevuti: " . print_r($headers, true));
|
error_log("Header ricevuti: " . print_r($headers, true));
|
||||||
|
|
||||||
// Normalizza gli header (solo trim)
|
// Normalize headers
|
||||||
$normalized_headers = array_map('trim', $headers);
|
$normalized_headers = array_map(function ($header) {
|
||||||
|
return trim((string)$header);
|
||||||
|
}, $headers);
|
||||||
|
|
||||||
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
||||||
error_log("Action values - action1: '$action1', action2: '$action2', action3: '$action3', action4: '$action4'");
|
error_log("Action values - action1: '$action1', action2: '$action2', action3: '$action3', action4: '$action4'");
|
||||||
|
|
||||||
// Trova gli indici delle colonne
|
// Find package-related column indexes
|
||||||
$action1_index = array_search($action1, $normalized_headers);
|
$package_index = array_search($package_header, $normalized_headers, true);
|
||||||
$action2_index = array_search($action2, $normalized_headers);
|
$other_test_index = array_search($other_test_header, $normalized_headers, true);
|
||||||
$action3_index = array_search($action3, $normalized_headers);
|
$only_colorfastness_index = array_search($only_colorfastness_header, $normalized_headers, true);
|
||||||
$action4_index = array_search($action4, $normalized_headers);
|
$only_chemical_index = array_search($only_chemical_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
if ($package_index === false) {
|
||||||
|
throw new Exception("Colonna PACKAGE non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log(
|
||||||
|
"Indici package - PACKAGE: " . var_export($package_index, true) .
|
||||||
|
", Other test from Control Matrix: " . var_export($other_test_index, true) .
|
||||||
|
", Only Colorfastness package: " . var_export($only_colorfastness_index, true) .
|
||||||
|
", Only Chemical package: " . var_export($only_chemical_index, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PART 1
|
||||||
|
* Aggregate rows by action1 and split action2 into action3 + action4
|
||||||
|
* If it fails, continue with PART 2 only
|
||||||
|
*/
|
||||||
|
$part1_applied = false;
|
||||||
|
|
||||||
|
$action1_index = array_search($action1, $normalized_headers, true);
|
||||||
|
$action2_index = array_search($action2, $normalized_headers, true);
|
||||||
|
$action3_index = array_search($action3, $normalized_headers, true);
|
||||||
|
$action4_index = array_search($action4, $normalized_headers, true);
|
||||||
|
|
||||||
if ($action1_index === false || $action2_index === false || $action3_index === false || $action4_index === false) {
|
if ($action1_index === false || $action2_index === false || $action3_index === false || $action4_index === false) {
|
||||||
throw new Exception("Colonne non trovate - action1: '$action1' (index: " . var_export($action1_index, true) . "), action2: '$action2' (index: " . var_export($action2_index, true) . "), action3: '$action3' (index: " . var_export($action3_index, true) . "), action4: '$action4' (index: " . var_export($action4_index, true) . ")");
|
error_log(
|
||||||
|
"Unable to apply routine part 1. Package merge logic has been applied only. " .
|
||||||
|
"Missing columns - action1: '$action1' (index: " . var_export($action1_index, true) . ")" .
|
||||||
|
", action2: '$action2' (index: " . var_export($action2_index, true) . ")" .
|
||||||
|
", action3: '$action3' (index: " . var_export($action3_index, true) . ")" .
|
||||||
|
", action4: '$action4' (index: " . var_export($action4_index, true) . ")"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
error_log("Indici colonne part 1 - action1: $action1_index, action2: $action2_index, action3: $action3_index, action4: $action4_index");
|
||||||
|
|
||||||
|
$grouped_data = [];
|
||||||
|
|
||||||
|
foreach ($excelData as $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida, manca 'data' per excelrow " . ($row['excelrow'] ?? 'N/A'));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $row['data'][$action1_index] ?? '';
|
||||||
|
$key = trim((string)$key);
|
||||||
|
$key = $key === '' ? '_empty_' : $key;
|
||||||
|
|
||||||
|
if (!isset($grouped_data[$key])) {
|
||||||
|
$grouped_data[$key] = [
|
||||||
|
'data' => $row['data'],
|
||||||
|
'excelrow' => [($row['excelrow'] ?? '')],
|
||||||
|
'style_codes' => [],
|
||||||
|
'style_descriptions' => []
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$grouped_data[$key]['excelrow'][] = ($row['excelrow'] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split STYLE CODE + STYLE DESCRIPTION
|
||||||
|
$action2_value = trim((string)($row['data'][$action2_index] ?? ''));
|
||||||
|
|
||||||
|
if ($action2_value !== '') {
|
||||||
|
$parts = explode(' - ', $action2_value, 2);
|
||||||
|
$style_code = trim((string)($parts[0] ?? ''));
|
||||||
|
$style_description = trim((string)($parts[1] ?? ''));
|
||||||
|
|
||||||
|
if ($style_code !== '') {
|
||||||
|
$grouped_data[$key]['style_codes'][] = $style_code;
|
||||||
|
}
|
||||||
|
if ($style_description !== '') {
|
||||||
|
$grouped_data[$key]['style_descriptions'][] = $style_description;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log("Valore vuoto in action2 per excelrow " . ($row['excelrow'] ?? 'N/A'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_excel_data = [];
|
||||||
|
|
||||||
|
foreach ($grouped_data as $key => $group) {
|
||||||
|
$row_data = $group['data'];
|
||||||
|
|
||||||
|
// Update STYLE CODE and STYLE DESCRIPTION with aggregated unique values
|
||||||
|
$row_data[$action3_index] = implode(' - ', array_unique($group['style_codes']));
|
||||||
|
$row_data[$action4_index] = implode(' - ', array_unique($group['style_descriptions']));
|
||||||
|
|
||||||
|
// Concatenate excelrow values with "+"
|
||||||
|
$excelrow_clean = array_filter($group['excelrow'], function ($value) {
|
||||||
|
return $value !== null && $value !== '';
|
||||||
|
});
|
||||||
|
|
||||||
|
$excelrow_value = count($excelrow_clean) > 1
|
||||||
|
? implode('+', $excelrow_clean)
|
||||||
|
: (reset($excelrow_clean) ?: '');
|
||||||
|
|
||||||
|
$new_excel_data[] = [
|
||||||
|
'data' => $row_data,
|
||||||
|
'excelrow' => $excelrow_value
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$excelData = $new_excel_data;
|
||||||
|
$part1_applied = true;
|
||||||
|
|
||||||
|
error_log("Routine part 1 completata - Righe aggregate: " . count($new_excel_data));
|
||||||
|
error_log("Excelrow aggregati part 1: " . print_r(array_column($new_excel_data, 'excelrow'), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
error_log("Indici colonne - action1: $action1_index, action2: $action2_index, action3: $action3_index, action4: $action4_index");
|
/**
|
||||||
|
* PART 2
|
||||||
// Raggruppa le righe per il valore in action1 (colonna K)
|
* Merge package-related columns into PACKAGE
|
||||||
$grouped_data = [];
|
* Always applied if PACKAGE exists
|
||||||
foreach ($excelData as $row) {
|
*/
|
||||||
|
foreach ($excelData as $index => $row) {
|
||||||
if (!isset($row['data']) || !is_array($row['data'])) {
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
error_log("Riga non valida, manca 'data' per excelrow {$row['excelrow']}");
|
error_log("Riga non valida nella part 2, manca 'data' all'indice $index");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$key = $row['data'][$action1_index] ?? '';
|
|
||||||
$key = empty($key) ? '_empty_' : $key;
|
$package_values = [];
|
||||||
if (!isset($grouped_data[$key])) {
|
|
||||||
$grouped_data[$key] = [
|
$value_package = trim((string)($row['data'][$package_index] ?? ''));
|
||||||
'data' => $row['data'],
|
$value_other_test = $other_test_index !== false ? trim((string)($row['data'][$other_test_index] ?? '')) : '';
|
||||||
'excelrow' => [$row['excelrow']],
|
$value_only_colorfastness = $only_colorfastness_index !== false ? trim((string)($row['data'][$only_colorfastness_index] ?? '')) : '';
|
||||||
'style_codes' => [],
|
$value_only_chemical = $only_chemical_index !== false ? trim((string)($row['data'][$only_chemical_index] ?? '')) : '';
|
||||||
'style_descriptions' => []
|
|
||||||
];
|
if ($value_package !== '') {
|
||||||
} else {
|
$package_values[] = $value_package;
|
||||||
$grouped_data[$key]['excelrow'][] = $row['excelrow'];
|
}
|
||||||
|
if ($value_other_test !== '') {
|
||||||
|
$package_values[] = $value_other_test;
|
||||||
|
}
|
||||||
|
if ($value_only_colorfastness !== '') {
|
||||||
|
$package_values[] = $value_only_colorfastness;
|
||||||
|
}
|
||||||
|
if ($value_only_chemical !== '') {
|
||||||
|
$package_values[] = $value_only_chemical;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separa il valore in action2 (STYLE CODE + STYLE DESCRIPTION)
|
$package_values = array_unique($package_values);
|
||||||
$action2_value = $row['data'][$action2_index] ?? '';
|
|
||||||
if (!empty($action2_value)) {
|
$excelData[$index]['data'][$package_index] = implode(' - ', $package_values);
|
||||||
$parts = explode(' - ', trim($action2_value));
|
|
||||||
$style_code = $parts[0] ?? '';
|
|
||||||
$style_description = $parts[1] ?? '';
|
|
||||||
if (!empty($style_code)) {
|
|
||||||
$grouped_data[$key]['style_codes'][] = $style_code;
|
|
||||||
}
|
|
||||||
if (!empty($style_description)) {
|
|
||||||
$grouped_data[$key]['style_descriptions'][] = $style_description;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_log("Valore vuoto in action2 per excelrow {$row['excelrow']}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crea il nuovo array excel_data aggregato
|
error_log("Routine part 2 completata - Merge package applicato su " . count($excelData) . " righe");
|
||||||
$new_excel_data = [];
|
|
||||||
foreach ($grouped_data as $key => $group) {
|
if (!$part1_applied) {
|
||||||
$row_data = $group['data'];
|
error_log("Warning finale: routine part 1 non applicata, routine part 2 applicata correttamente");
|
||||||
// Aggiorna action3 (STYLE CODE) e action4 (STYLE DESCRIPTION) con valori aggregati
|
|
||||||
$row_data[$action3_index] = implode(' - ', array_unique($group['style_codes']));
|
|
||||||
$row_data[$action4_index] = implode(' - ', array_unique($group['style_descriptions']));
|
|
||||||
// Concatena gli excelrow con '+' per le righe aggregate
|
|
||||||
$excelrow_value = count($group['excelrow']) > 1 ? implode('+', $group['excelrow']) : $group['excelrow'][0];
|
|
||||||
$new_excel_data[] = [
|
|
||||||
'data' => $row_data,
|
|
||||||
'excelrow' => $excelrow_value
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifica excelData in-place
|
error_log("Routine Moncler completata con successo");
|
||||||
$excelData = $new_excel_data;
|
|
||||||
|
|
||||||
error_log("Routine Moncler completata - Righe aggregate: " . count($new_excel_data));
|
|
||||||
error_log("Excelrow aggregati: " . print_r(array_column($new_excel_data, 'excelrow'), true));
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Eccezione nella routine Moncler: " . $e->getMessage());
|
error_log("Eccezione nella routine Moncler: " . $e->getMessage());
|
||||||
throw $e;
|
throw $e;
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/routine_debug.log');
|
||||||
|
|
||||||
|
function applyRoutine(&$excelData, $routineData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initial log
|
||||||
|
error_log("Inizio esecuzione nuova routine: " . date('Y-m-d H:i:s'));
|
||||||
|
error_log("Dati routine: " . print_r($routineData, true));
|
||||||
|
error_log("Dati excel_data: " . print_r($excelData, true));
|
||||||
|
|
||||||
|
// Check if excelData is empty
|
||||||
|
if (empty($excelData)) {
|
||||||
|
throw new Exception("excelData è vuoto o non valido.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get headers from routine data
|
||||||
|
$headers = $routineData['xls_headers'] ?? [];
|
||||||
|
|
||||||
|
if (empty($headers)) {
|
||||||
|
throw new Exception("Nessun header trovato per la routine.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If headers arrive as JSON string, decode them
|
||||||
|
if (!is_array($headers) && is_string($headers)) {
|
||||||
|
$decoded_headers = json_decode($headers, true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded_headers)) {
|
||||||
|
$headers = $decoded_headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($headers) || empty($headers)) {
|
||||||
|
throw new Exception("Gli header della routine non sono validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Header ricevuti: " . print_r($headers, true));
|
||||||
|
|
||||||
|
// Normalize headers
|
||||||
|
$normalized_headers = array_map(function ($header) {
|
||||||
|
return trim((string)$header);
|
||||||
|
}, $headers);
|
||||||
|
|
||||||
|
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define source and target headers
|
||||||
|
*/
|
||||||
|
$parte_moncler_header = 'PARTE MONCLER';
|
||||||
|
$parte_fornitore_header = 'PARTE FORNITORE';
|
||||||
|
|
||||||
|
$descr_parte_moncler_header = 'DESCRIZIONE PARTE MONCLER';
|
||||||
|
$descr_parte_fornitore_header = 'DESCRIZIONE PARTE FORNITORE';
|
||||||
|
|
||||||
|
$colore_moncler_header = 'COLORE MONCLER';
|
||||||
|
$colore_fornitore_header = 'COLORE FORNITORE';
|
||||||
|
|
||||||
|
$composizione_tessile_header = 'COMPOSIZIONE TESSILE';
|
||||||
|
$composizione_totale_header = 'COMPOSIZIONE TOTALE';
|
||||||
|
|
||||||
|
$pacchetti_test_header = 'PACCHETTI TEST';
|
||||||
|
$test_addizionali_header = 'TEST ADDIZIONALI (A5 solo se richiesti dal cliente)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find indexes
|
||||||
|
*/
|
||||||
|
$parte_moncler_index = array_search($parte_moncler_header, $normalized_headers, true);
|
||||||
|
$parte_fornitore_index = array_search($parte_fornitore_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$descr_parte_moncler_index = array_search($descr_parte_moncler_header, $normalized_headers, true);
|
||||||
|
$descr_parte_fornitore_index = array_search($descr_parte_fornitore_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$colore_moncler_index = array_search($colore_moncler_header, $normalized_headers, true);
|
||||||
|
$colore_fornitore_index = array_search($colore_fornitore_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$composizione_tessile_index = array_search($composizione_tessile_header, $normalized_headers, true);
|
||||||
|
$composizione_totale_index = array_search($composizione_totale_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
$pacchetti_test_index = array_search($pacchetti_test_header, $normalized_headers, true);
|
||||||
|
$test_addizionali_index = array_search($test_addizionali_header, $normalized_headers, true);
|
||||||
|
|
||||||
|
error_log(
|
||||||
|
"Indici trovati - " .
|
||||||
|
"PARTE MONCLER: " . var_export($parte_moncler_index, true) .
|
||||||
|
", PARTE FORNITORE: " . var_export($parte_fornitore_index, true) .
|
||||||
|
", DESCRIZIONE PARTE MONCLER: " . var_export($descr_parte_moncler_index, true) .
|
||||||
|
", DESCRIZIONE PARTE FORNITORE: " . var_export($descr_parte_fornitore_index, true) .
|
||||||
|
", COLORE MONCLER: " . var_export($colore_moncler_index, true) .
|
||||||
|
", COLORE FORNITORE: " . var_export($colore_fornitore_index, true) .
|
||||||
|
", COMPOSIZIONE TESSILE: " . var_export($composizione_tessile_index, true) .
|
||||||
|
", COMPOSIZIONE TOTALE: " . var_export($composizione_totale_index, true) .
|
||||||
|
", PACCHETTI TEST: " . var_export($pacchetti_test_index, true) .
|
||||||
|
", TEST ADDIZIONALI: " . var_export($test_addizionali_index, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Required target columns must exist
|
||||||
|
if ($parte_moncler_index === false) {
|
||||||
|
throw new Exception("Colonna PARTE MONCLER non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($descr_parte_moncler_index === false) {
|
||||||
|
throw new Exception("Colonna DESCRIZIONE PARTE MONCLER non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($colore_moncler_index === false) {
|
||||||
|
throw new Exception("Colonna COLORE MONCLER non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($composizione_tessile_index === false) {
|
||||||
|
throw new Exception("Colonna COMPOSIZIONE TESSILE non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pacchetti_test_index === false) {
|
||||||
|
throw new Exception("Colonna PACCHETTI TEST non trovata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply merge row by row
|
||||||
|
*/
|
||||||
|
foreach ($excelData as $index => $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida, manca 'data' all'indice $index");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. PARTE MONCLER + PARTE FORNITORE -> PARTE MONCLER
|
||||||
|
$parte_values = [];
|
||||||
|
|
||||||
|
$value_parte_moncler = trim((string)($row['data'][$parte_moncler_index] ?? ''));
|
||||||
|
$value_parte_fornitore = $parte_fornitore_index !== false ? trim((string)($row['data'][$parte_fornitore_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_parte_moncler !== '') {
|
||||||
|
$parte_values[] = $value_parte_moncler;
|
||||||
|
}
|
||||||
|
if ($value_parte_fornitore !== '') {
|
||||||
|
$parte_values[] = $value_parte_fornitore;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parte_values = array_unique($parte_values);
|
||||||
|
$excelData[$index]['data'][$parte_moncler_index] = implode(' - ', $parte_values);
|
||||||
|
|
||||||
|
// 2. DESCRIZIONE PARTE MONCLER + DESCRIZIONE PARTE FORNITORE -> DESCRIZIONE PARTE MONCLER
|
||||||
|
$descr_values = [];
|
||||||
|
|
||||||
|
$value_descr_moncler = trim((string)($row['data'][$descr_parte_moncler_index] ?? ''));
|
||||||
|
$value_descr_fornitore = $descr_parte_fornitore_index !== false ? trim((string)($row['data'][$descr_parte_fornitore_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_descr_moncler !== '') {
|
||||||
|
$descr_values[] = $value_descr_moncler;
|
||||||
|
}
|
||||||
|
if ($value_descr_fornitore !== '') {
|
||||||
|
$descr_values[] = $value_descr_fornitore;
|
||||||
|
}
|
||||||
|
|
||||||
|
$descr_values = array_unique($descr_values);
|
||||||
|
$excelData[$index]['data'][$descr_parte_moncler_index] = implode(' - ', $descr_values);
|
||||||
|
|
||||||
|
// 3. COLORE MONCLER + COLORE FORNITORE -> COLORE MONCLER
|
||||||
|
$colore_values = [];
|
||||||
|
|
||||||
|
$value_colore_moncler = trim((string)($row['data'][$colore_moncler_index] ?? ''));
|
||||||
|
$value_colore_fornitore = $colore_fornitore_index !== false ? trim((string)($row['data'][$colore_fornitore_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_colore_moncler !== '') {
|
||||||
|
$colore_values[] = $value_colore_moncler;
|
||||||
|
}
|
||||||
|
if ($value_colore_fornitore !== '') {
|
||||||
|
$colore_values[] = $value_colore_fornitore;
|
||||||
|
}
|
||||||
|
|
||||||
|
$colore_values = array_unique($colore_values);
|
||||||
|
$excelData[$index]['data'][$colore_moncler_index] = implode(' - ', $colore_values);
|
||||||
|
|
||||||
|
// 4. COMPOSIZIONE TESSILE + COMPOSIZIONE TOTALE -> COMPOSIZIONE TESSILE
|
||||||
|
$composizione_values = [];
|
||||||
|
|
||||||
|
$value_composizione_tessile = trim((string)($row['data'][$composizione_tessile_index] ?? ''));
|
||||||
|
$value_composizione_totale = $composizione_totale_index !== false ? trim((string)($row['data'][$composizione_totale_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_composizione_tessile !== '') {
|
||||||
|
$composizione_values[] = $value_composizione_tessile;
|
||||||
|
}
|
||||||
|
if ($value_composizione_totale !== '') {
|
||||||
|
$composizione_values[] = $value_composizione_totale;
|
||||||
|
}
|
||||||
|
|
||||||
|
$composizione_values = array_unique($composizione_values);
|
||||||
|
$excelData[$index]['data'][$composizione_tessile_index] = implode(' - ', $composizione_values);
|
||||||
|
|
||||||
|
// 5. PACCHETTI TEST + TEST ADDIZIONALI -> PACCHETTI TEST
|
||||||
|
$pacchetti_values = [];
|
||||||
|
|
||||||
|
$value_pacchetti_test = trim((string)($row['data'][$pacchetti_test_index] ?? ''));
|
||||||
|
$value_test_addizionali = $test_addizionali_index !== false ? trim((string)($row['data'][$test_addizionali_index] ?? '')) : '';
|
||||||
|
|
||||||
|
if ($value_pacchetti_test !== '') {
|
||||||
|
$pacchetti_values[] = $value_pacchetti_test;
|
||||||
|
}
|
||||||
|
if ($value_test_addizionali !== '') {
|
||||||
|
$pacchetti_values[] = $value_test_addizionali;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pacchetti_values = array_unique($pacchetti_values);
|
||||||
|
$excelData[$index]['data'][$pacchetti_test_index] = implode(' - ', $pacchetti_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Nuova routine completata con successo. Righe elaborate: " . count($excelData));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Eccezione nella nuova routine: " . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,9 +12,75 @@ try {
|
|||||||
|
|
||||||
$iddatadb = intval($_POST['iddatadb']);
|
$iddatadb = intval($_POST['iddatadb']);
|
||||||
$idclient = isset($_POST['idclient']) ? (is_numeric($_POST['idclient']) ? intval($_POST['idclient']) : null) : null;
|
$idclient = isset($_POST['idclient']) ? (is_numeric($_POST['idclient']) ? intval($_POST['idclient']) : null) : null;
|
||||||
$db = DBHandlerSelect::getInstance();
|
$clienteFornitoreId = isset($_POST['cliente_fornitore_id']) ? (is_numeric($_POST['cliente_fornitore_id']) ? intval($_POST['cliente_fornitore_id']) : null) : null;
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// ---------------- FIXED FIELDS (template_fixed_mapping) ----------------
|
||||||
|
|
||||||
|
// ALIAS: fixed_field_key "logico" -> colonna reale su datadb
|
||||||
|
// (NON tocchiamo MySQL, gestiamo solo qui la traduzione)
|
||||||
|
$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',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 1) Recupera templateid dalla riga datadb (serve per sapere quali fixed_field_key sono permessi)
|
||||||
|
$stmtTpl = $pdo->prepare("SELECT templateid FROM datadb WHERE iddatadb = ?");
|
||||||
|
$stmtTpl->execute([$iddatadb]);
|
||||||
|
$tplRow = $stmtTpl->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$templateId = isset($tplRow['templateid']) ? (int)$tplRow['templateid'] : 0;
|
||||||
|
if ($templateId <= 0) {
|
||||||
|
throw new Exception("Template non trovato per iddatadb=$iddatadb");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Recupera elenco fixed fields visibili per quel template
|
||||||
|
$fxStmt = $pdo->prepare("
|
||||||
|
SELECT fixed_field_key, data_type, is_required, default_value
|
||||||
|
FROM template_fixed_mapping
|
||||||
|
WHERE template_id = ? AND is_visible_import = 1
|
||||||
|
");
|
||||||
|
$fxStmt->execute([$templateId]);
|
||||||
|
$fixedList = $fxStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// 3) Crea whitelist LOGICA: fixed_field_key => metadata
|
||||||
|
$fixedWhitelist = [];
|
||||||
|
foreach ($fixedList as $fx) {
|
||||||
|
$k = (string)$fx['fixed_field_key'];
|
||||||
|
|
||||||
|
// sicurezza: key ammessa solo se "safe"
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_]+$/', $k)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fixedWhitelist[$k] = [
|
||||||
|
'data_type' => (string)$fx['data_type'], // INT | DATE
|
||||||
|
'is_required' => (int)$fx['is_required'],
|
||||||
|
'default_value' => $fx['default_value'] ?? null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3b) Crea whitelist REALE: colonna datadb reale => metadata
|
||||||
|
$realWhitelist = [];
|
||||||
|
foreach ($fixedWhitelist as $logicalKey => $meta) {
|
||||||
|
$realCol = $fixedAliasMap[$logicalKey] ?? $logicalKey;
|
||||||
|
|
||||||
|
// sicurezza: anche la colonna reale deve essere "safe"
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_]+$/', $realCol)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$realWhitelist[$realCol] = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- DETAILS (import_data_details) ----------------
|
||||||
$data = $_POST;
|
$data = $_POST;
|
||||||
$details = [];
|
$details = [];
|
||||||
|
|
||||||
@@ -56,27 +122,88 @@ try {
|
|||||||
|
|
||||||
foreach ($changed as $mappingId => $values) {
|
foreach ($changed as $mappingId => $values) {
|
||||||
$updateStmt->execute([
|
$updateStmt->execute([
|
||||||
':newValue' => $values['new'],
|
':newValue' => $values['new'],
|
||||||
':iddatadb' => $iddatadb,
|
':iddatadb' => $iddatadb,
|
||||||
':mappingId' => $mappingId
|
':mappingId' => $mappingId
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Aggiorna idclient in datadb
|
// ---------------- UPDATE datadb: idclient + FIXED FIELDS ----------------
|
||||||
|
$setParts = [];
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// 5a) idclient (se presente)
|
||||||
if (isset($idclient)) {
|
if (isset($idclient)) {
|
||||||
$updateStmt = $pdo->prepare("
|
$setParts[] = "idclient = ?";
|
||||||
UPDATE datadb
|
$params[] = $idclient;
|
||||||
SET idclient = :idclient
|
}
|
||||||
WHERE iddatadb = :iddatadb
|
|
||||||
");
|
// 5a2) cliente_fornitore_id (se presente)
|
||||||
$updateStmt->execute([
|
if (isset($clienteFornitoreId)) {
|
||||||
':idclient' => $idclient,
|
$setParts[] = "cliente_fornitore_id = ?";
|
||||||
':iddatadb' => $iddatadb
|
$params[] = $clienteFornitoreId;
|
||||||
]);
|
}
|
||||||
$response['message'] = !empty($changed) ? "Updated details and idclient successfully" : "Updated idclient successfully";
|
|
||||||
|
// 5b) fixed fields dal POST
|
||||||
|
// QUI è il punto chiave: accettiamo SOLO colonne reali (realWhitelist),
|
||||||
|
// ma se dal JS arrivassero ancora key logiche, funzionerebbe uguale
|
||||||
|
// perché sotto controlliamo anche l'alias.
|
||||||
|
foreach ($realWhitelist as $realCol => $meta) {
|
||||||
|
|
||||||
|
$postKeyToRead = null;
|
||||||
|
|
||||||
|
// Caso 1: POST contiene già la colonna reale
|
||||||
|
if (array_key_exists($realCol, $_POST)) {
|
||||||
|
$postKeyToRead = $realCol;
|
||||||
|
} else {
|
||||||
|
// Caso 2: POST contiene la key logica -> troviamo quale logica mappa su questa colonna reale
|
||||||
|
// (fallback, utile se non hai ancora aggiornato il JS)
|
||||||
|
foreach ($fixedAliasMap as $logical => $mappedReal) {
|
||||||
|
if ($mappedReal === $realCol && array_key_exists($logical, $_POST)) {
|
||||||
|
$postKeyToRead = $logical;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($postKeyToRead === null) {
|
||||||
|
continue; // non inviato
|
||||||
|
}
|
||||||
|
|
||||||
|
$val = $_POST[$postKeyToRead];
|
||||||
|
|
||||||
|
// Normalizzazione per tipo
|
||||||
|
if ($meta['data_type'] === 'DATE') {
|
||||||
|
$val = trim((string)$val);
|
||||||
|
$val = ($val === '') ? null : $val; // atteso formato Y-m-d
|
||||||
|
} else { // INT
|
||||||
|
$val = trim((string)$val);
|
||||||
|
$val = ($val === '') ? null : (int)$val;
|
||||||
|
}
|
||||||
|
|
||||||
|
$setParts[] = "`$realCol` = ?";
|
||||||
|
$params[] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// esegui update solo se c'è qualcosa da aggiornare
|
||||||
|
if (!empty($setParts)) {
|
||||||
|
$params[] = $iddatadb;
|
||||||
|
|
||||||
|
$sqlUpd = "UPDATE datadb SET " . implode(", ", $setParts) . " WHERE iddatadb = ?";
|
||||||
|
$updStmt = $pdo->prepare($sqlUpd);
|
||||||
|
$updStmt->execute($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messaggio risposta (mantengo la tua logica ma includo fixed)
|
||||||
|
if (!empty($setParts) && !empty($changed)) {
|
||||||
|
$response['message'] = "Updated details and datadb fields successfully";
|
||||||
|
} elseif (!empty($setParts)) {
|
||||||
|
$response['message'] = "Updated datadb fields successfully";
|
||||||
|
} elseif (!empty($changed)) {
|
||||||
|
$response['message'] = "Updated details successfully";
|
||||||
} else {
|
} else {
|
||||||
$response['message'] = !empty($changed) ? "Updated details successfully" : "No changes found";
|
$response['message'] = "No changes found";
|
||||||
}
|
}
|
||||||
|
|
||||||
$response['success'] = true;
|
$response['success'] = true;
|
||||||
|
|||||||
@@ -20,19 +20,82 @@ $mappingId = $data['id'];
|
|||||||
$mappingType = $data['mapping_type'] ?? '';
|
$mappingType = $data['mapping_type'] ?? '';
|
||||||
$excelColumn = $data['excel_column'] ?? null;
|
$excelColumn = $data['excel_column'] ?? null;
|
||||||
$manualDefault = $data['manual_default'] ?? null;
|
$manualDefault = $data['manual_default'] ?? null;
|
||||||
|
|
||||||
|
$autoValue = $data['auto_value'] ?? 'none';
|
||||||
$tablename = $data['tablename'] ?? '';
|
$tablename = $data['tablename'] ?? '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("UPDATE template_mapping SET is_manual = ?, excel_column = ?, manual_default = ? WHERE id = ?");
|
// Normalize mapping type
|
||||||
$isManual = ($mappingType === 'manual') ? 1 : 0;
|
$allowedTypes = ['', 'xls', 'manual', 'auto'];
|
||||||
$result = $stmt->execute([$isManual, $excelColumn, $manualDefault, $mappingId]);
|
if (!in_array($mappingType, $allowedTypes, true)) {
|
||||||
|
echo json_encode(["success" => false, "message" => "Invalid mapping_type"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize auto_value
|
||||||
|
$allowedAuto = ['none', 'import_date', 'import_time', 'export_date', 'export_time'];
|
||||||
|
if (!in_array($autoValue, $allowedAuto, true)) {
|
||||||
|
$autoValue = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide what to persist based on mapping_type
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
|
||||||
|
if ($mappingType === 'xls') {
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = $excelColumn ?: null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
} elseif ($mappingType === 'manual') {
|
||||||
|
$isManual = 1;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = $manualDefault;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
} elseif ($mappingType === 'auto') {
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = $autoValue ?: 'none';
|
||||||
|
} else {
|
||||||
|
// reset
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
UPDATE template_mapping
|
||||||
|
SET
|
||||||
|
is_manual = ?,
|
||||||
|
excel_column = ?,
|
||||||
|
manual_default = ?,
|
||||||
|
auto_value = ?
|
||||||
|
WHERE id = ?
|
||||||
|
");
|
||||||
|
|
||||||
|
$result = $stmt->execute([$isManual, $excelToSave, $manualToSave, $autoToSave, $mappingId]);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
echo json_encode(["success" => false, "message" => "Database update failed"]);
|
echo json_encode(["success" => false, "message" => "Database update failed"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode(["success" => true, "message" => "Mapping updated successfully", "data" => $data]); // Aggiunto debug
|
echo json_encode([
|
||||||
|
"success" => true,
|
||||||
|
"message" => "Mapping updated successfully",
|
||||||
|
"saved" => [
|
||||||
|
"id" => (int)$mappingId,
|
||||||
|
"mapping_type" => $mappingType,
|
||||||
|
"is_manual" => $isManual,
|
||||||
|
"excel_column" => $excelToSave,
|
||||||
|
"manual_default" => $manualToSave,
|
||||||
|
"auto_value" => $autoToSave
|
||||||
|
]
|
||||||
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
|
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
+128
-39
@@ -4,6 +4,7 @@ include('include/headscript.php');
|
|||||||
|
|
||||||
$dbHandler = DBHandlerSelect::getInstance();
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
$pdo = $dbHandler->getConnection();
|
$pdo = $dbHandler->getConnection();
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
@@ -19,6 +20,21 @@ try {
|
|||||||
$pdo->beginTransaction();
|
$pdo->beginTransaction();
|
||||||
$results = [];
|
$results = [];
|
||||||
|
|
||||||
|
// Custom fields statements (child table)
|
||||||
|
$stmtUpsertCF = $pdo->prepare("
|
||||||
|
INSERT INTO identification_parts_customfields (part_id, field_id, value_id, value_text)
|
||||||
|
VALUES (:part_id, :field_id, :value_id, :value_text)
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
value_id = VALUES(value_id),
|
||||||
|
value_text = VALUES(value_text),
|
||||||
|
updated_at = NOW()
|
||||||
|
");
|
||||||
|
|
||||||
|
$stmtDeleteCF = $pdo->prepare("
|
||||||
|
DELETE FROM identification_parts_customfields
|
||||||
|
WHERE part_id = :part_id AND field_id = :field_id
|
||||||
|
");
|
||||||
|
|
||||||
foreach ($parts as $part) {
|
foreach ($parts as $part) {
|
||||||
$partId = $part['id'] ?? null;
|
$partId = $part['id'] ?? null;
|
||||||
$partNumber = $part['part_number'] ?? null;
|
$partNumber = $part['part_number'] ?? null;
|
||||||
@@ -28,50 +44,123 @@ try {
|
|||||||
$note = $part['note'] ?? null;
|
$note = $part['note'] ?? null;
|
||||||
$dateexpiry = $part['dateexpiry'] ?? null;
|
$dateexpiry = $part['dateexpiry'] ?? null;
|
||||||
|
|
||||||
if ($partDescription || $note || $dateexpiry) {
|
// Extra field (0/1)
|
||||||
if ($partId) {
|
$extraFieldId = $part['extra_field_id'] ?? null;
|
||||||
// UPDATE se la parte esiste
|
$extraValueId = $part['extra_value_id'] ?? null;
|
||||||
$stmt = $pdo->prepare("UPDATE identification_parts
|
$extraValueText = $part['extra_value_text'] ?? null;
|
||||||
SET part_number = :part_number,
|
|
||||||
part_description = :part_description,
|
// Normalizza vuoti
|
||||||
mix = :mix,
|
if ($extraFieldId !== null && $extraFieldId !== '') $extraFieldId = (int)$extraFieldId;
|
||||||
idmatrice = :idmatrice,
|
else $extraFieldId = null;
|
||||||
note = :note,
|
if ($extraValueId !== null && $extraValueId !== '') $extraValueId = (int)$extraValueId;
|
||||||
dateexpiry = :dateexpiry,
|
else $extraValueId = null;
|
||||||
updated_at = NOW()
|
if ($extraValueText !== null) {
|
||||||
WHERE id = :id");
|
$extraValueText = trim((string)$extraValueText);
|
||||||
$stmt->execute([
|
if ($extraValueText === '') $extraValueText = null;
|
||||||
':id' => $partId,
|
}
|
||||||
':part_number' => $partNumber,
|
|
||||||
':part_description' => $partDescription,
|
if ($partId) {
|
||||||
':mix' => $mix,
|
// UPDATE se la parte esiste (sempre)
|
||||||
':idmatrice' => $idmatrice,
|
$stmt = $pdo->prepare("UPDATE identification_parts
|
||||||
':note' => $note,
|
SET part_number = :part_number,
|
||||||
':dateexpiry' => $dateexpiry,
|
part_description = :part_description,
|
||||||
]);
|
mix = :mix,
|
||||||
$results[] = ['part_id' => $partId, 'part_number' => $partNumber, 'message' => 'Parte aggiornata con successo'];
|
idmatrice = :idmatrice,
|
||||||
} else {
|
note = :note,
|
||||||
// INSERT per nuova parte
|
dateexpiry = :dateexpiry,
|
||||||
$stmt = $pdo->prepare("INSERT INTO identification_parts
|
updated_at = NOW()
|
||||||
(iddatadb, part_number, part_description, mix, idmatrice, note, dateexpiry, created_at, updated_at)
|
WHERE id = :id");
|
||||||
VALUES (:iddatadb, :part_number, :part_description, :mix, :idmatrice, :note, :dateexpiry, NOW(), NOW())");
|
$stmt->execute([
|
||||||
$stmt->execute([
|
':id' => $partId,
|
||||||
':iddatadb' => $iddatadb,
|
':part_number' => $partNumber,
|
||||||
':part_number' => $partNumber,
|
':part_description' => $partDescription,
|
||||||
':part_description' => $partDescription,
|
':mix' => $mix,
|
||||||
':mix' => $mix,
|
':idmatrice' => $idmatrice,
|
||||||
':idmatrice' => $idmatrice,
|
':note' => $note,
|
||||||
':note' => $note,
|
':dateexpiry' => $dateexpiry,
|
||||||
':dateexpiry' => $dateexpiry,
|
]);
|
||||||
]);
|
|
||||||
$newId = $pdo->lastInsertId();
|
// Save extra custom field (if provided)
|
||||||
$results[] = ['part_id' => $newId, 'part_number' => $partNumber, 'message' => 'Parte salvata con successo'];
|
if ($extraFieldId !== null) {
|
||||||
|
if ($extraValueId === null && $extraValueText === null) {
|
||||||
|
$stmtDeleteCF->execute([
|
||||||
|
':part_id' => $partId,
|
||||||
|
':field_id' => $extraFieldId,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$stmtUpsertCF->execute([
|
||||||
|
':part_id' => $partId,
|
||||||
|
':field_id' => $extraFieldId,
|
||||||
|
':value_id' => $extraValueId,
|
||||||
|
':value_text' => $extraValueText,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$cf_row = null;
|
||||||
|
if ($extraFieldId !== null) {
|
||||||
|
$chk = $pdo->prepare("SELECT id, value_id, value_text FROM identification_parts_customfields WHERE part_id = ? AND field_id = ?");
|
||||||
|
$chk->execute([$partId, $extraFieldId]);
|
||||||
|
$cf_row = $chk->fetch(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[] = [
|
||||||
|
'part_id' => $partId,
|
||||||
|
'part_number' => $partNumber,
|
||||||
|
'message' => 'Parte aggiornata con successo',
|
||||||
|
'cf_row' => $cf_row
|
||||||
|
];
|
||||||
|
} else if ($partDescription || $note || $dateexpiry) {
|
||||||
|
// INSERT per nuova parte (solo se ha contenuto)
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO identification_parts
|
||||||
|
(iddatadb, part_number, part_description, mix, idmatrice, note, dateexpiry, created_at, updated_at)
|
||||||
|
VALUES (:iddatadb, :part_number, :part_description, :mix, :idmatrice, :note, :dateexpiry, NOW(), NOW())");
|
||||||
|
$stmt->execute([
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix,
|
||||||
|
':idmatrice' => $idmatrice,
|
||||||
|
':note' => $note,
|
||||||
|
':dateexpiry' => $dateexpiry,
|
||||||
|
]);
|
||||||
|
$newId = (int)$pdo->lastInsertId();
|
||||||
|
|
||||||
|
if ($extraFieldId !== null) {
|
||||||
|
if ($extraValueId === null && $extraValueText === null) {
|
||||||
|
$stmtDeleteCF->execute([
|
||||||
|
':part_id' => $newId,
|
||||||
|
':field_id' => $extraFieldId,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$stmtUpsertCF->execute([
|
||||||
|
':part_id' => $newId,
|
||||||
|
':field_id' => $extraFieldId,
|
||||||
|
':value_id' => $extraValueId,
|
||||||
|
':value_text' => $extraValueText,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[] = [
|
||||||
|
'part_id' => $newId,
|
||||||
|
'part_number' => $partNumber,
|
||||||
|
'message' => 'Parte salvata con successo'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdo->commit();
|
$pdo->commit();
|
||||||
echo json_encode(['success' => true, 'results' => $results]);
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'results' => $results,
|
||||||
|
'debug_last' => [
|
||||||
|
'extra_field_id' => $extraFieldId ?? null,
|
||||||
|
'extra_value_id' => $extraValueId ?? null,
|
||||||
|
'extra_value_text' => $extraValueText ?? null,
|
||||||
|
'part_id' => $partId ?? ($newId ?? null),
|
||||||
|
]
|
||||||
|
]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$pdo->rollBack();
|
$pdo->rollBack();
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$iddatadb = $data['iddatadb'] ?? null;
|
||||||
|
$partIds = $data['partIds'] ?? [];
|
||||||
|
$photoList = $data['photoList'] ?? null;
|
||||||
|
|
||||||
|
if ($iddatadb) {
|
||||||
|
if (count($partIds) != 0) {
|
||||||
|
$idList = array_values(array_map('intval', $partIds));
|
||||||
|
$placeholders = [];
|
||||||
|
$parameters = [':iddatadb' => $iddatadb];
|
||||||
|
|
||||||
|
foreach ($idList as $index => $id) {
|
||||||
|
$paramName = ":id{$index}";
|
||||||
|
$placeholders[] = $paramName;
|
||||||
|
$parameters[$paramName] = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'UPDATE identification_parts SET iddatadb = :iddatadb WHERE id IN (' . implode(',', $placeholders) . ')';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($photoList) != 0) {
|
||||||
|
$placeholders = [];
|
||||||
|
$parameters = [':iddatadb' => $iddatadb];
|
||||||
|
|
||||||
|
foreach ($photoList as $index => $photo) {
|
||||||
|
$paramName = ":photo{$index}";
|
||||||
|
$placeholders[] = $paramName;
|
||||||
|
$parameters[$paramName] = $photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('UPDATE datadb_photos SET iddatadb = :iddatadb WHERE file_path IN (' . implode(',', $placeholders) . ')');
|
||||||
|
$stmt->execute($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'message' => '']);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,60 +1,881 @@
|
|||||||
{
|
{
|
||||||
"@odata.context": "https:\/\/93.43.5.102\/limsapi\/api\/odata\/$metadata#SchemaCustomField",
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#SchemaCustomField",
|
||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 41,
|
"IdSchemaCustomFields": 41,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Labostudio",
|
"Nome": "Labostudio",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 42,
|
"IdSchemaCustomFields": 42,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Schema 1",
|
"Nome": "Schema 1",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 43,
|
"IdSchemaCustomFields": 43,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Schema1",
|
"Nome": "Schema1",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 44,
|
"IdSchemaCustomFields": 44,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Cuoio\/Pelle Standard \/ Leather",
|
"Nome": "Cuoio\/Pelle Standard \/ Leather",
|
||||||
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 45,
|
"IdSchemaCustomFields": 45,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Borse",
|
"Nome": "Borse",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 46,
|
"IdSchemaCustomFields": 46,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Borse Burberry",
|
"Nome": "Borse Burberry",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 47,
|
"IdSchemaCustomFields": 47,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "pelle calzatura",
|
"Nome": "pelle calzatura",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 48,
|
"IdSchemaCustomFields": 48,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Standard Generico \/ Generic Standard",
|
"Nome": "Standard Generico \/ Generic Standard",
|
||||||
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 49,
|
"IdSchemaCustomFields": 49,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Accessori Metallici \/ Metallic Accessories",
|
"Nome": "Accessori Metallici \/ Metallic Accessories",
|
||||||
"Descrizione": "Schema per tutti gli Accessori Metallici\r\n\r\n\r\n"
|
"Descrizione": "Schema per tutti gli Accessori Metallici\r\n\r\n\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 50,
|
"IdSchemaCustomFields": 50,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Tessile \/ Textiles",
|
"Nome": "Tessile \/ Textiles",
|
||||||
"Descrizione": "Schema per tutti i Tessuti\r\n"
|
"Descrizione": "Schema per tutti i Tessuti\r\n"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 52,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Brasport",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 54,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel Calzatura",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 55,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Burberry",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 57,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Ralph Lauren - Tessile",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in tessuto per Ralph Lauren.\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 58,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LIU JO",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 59,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Migrazione tra Componenti",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 60,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Prova Outsourcing",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 61,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Marc Jacobs",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 62,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "A. TESTONI",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 63,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel CHINA PROJECT",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 66,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GUESS",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 68,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Valentino",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 69,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DESIGUAL",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 70,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FENDI PELLETTERIA",
|
||||||
|
"Descrizione": "Solo per FENDI Pelletteria_INGLESE\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 71,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Cuoio\/Pelle Standard ACCREDIA",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 72,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_BALLY",
|
||||||
|
"Descrizione": "sia per calzatura che pelletteria. Aggiunto campo TEST DESCRIPTION, compreso nella fatturazione per le divisioni pelletteria.\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 73,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Ralph Lauren - Leather",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 74,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Ralph Lauren - Fabric",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 76,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "NORDSTROM",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 77,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ONWARD LUXURY GROUP",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 78,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "P&G SRL_Progetto Durability",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 79,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Bally qualsiasi divisione",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 80,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FENDI CALZATURA",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 81,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LouBoutin",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 82,
|
"IdSchemaCustomFields": 82,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "MONCLER Brand",
|
"Nome": "MONCLER Brand",
|
||||||
"Descrizione": "Da utilizzare solo per il Brand Diretto\r\nGR 19\/03\/2024"
|
"Descrizione": "Da utilizzare solo per il Brand Diretto\r\nGR 19\/03\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 83,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "JIMMY CHOO",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 84,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Yves Saint Laurent",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 85,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BENETTON",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 86,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "UPLOAD REPORT",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 87,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes Calzatura",
|
||||||
|
"Descrizione": "\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 88,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "C&A",
|
||||||
|
"Descrizione": "Schema per fornitori e C&A diretto\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 89,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AMERICAN EAGLE",
|
||||||
|
"Descrizione": "Schema per American Eagle\/Todd snyder\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 91,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Ferragamo",
|
||||||
|
"Descrizione": "\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 93,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Alexander McQueen",
|
||||||
|
"Descrizione": "\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 95,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Balenciaga Pelletteria",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 96,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DUNHILL",
|
||||||
|
"Descrizione": "SCHEMA DUNHILL tutti i tipi di campioni\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 97,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PRELIEVI ACQUE",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 98,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LouBoutin_Tossicologico",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 99,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ROBAN'S ",
|
||||||
|
"Descrizione": "tutte le divisioni\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 100,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PROGETTO LUGGAGE",
|
||||||
|
"Descrizione": "Progetto Luggage Hermes\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 102,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Balmain",
|
||||||
|
"Descrizione": "Schema per tutti i campioni Balmain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 103,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ZDHC",
|
||||||
|
"Descrizione": "Schema di Riferimento ZDHC Wastewaters"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 104,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GUCCI CDC 4172",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 105,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ASOS",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 106,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_BOUX AVENUE",
|
||||||
|
"Descrizione": "28\/09 no indicazioni su esigenze di fatturazione (detto da Frosini)\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 107,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BONPOINT",
|
||||||
|
"Descrizione": "05\/10 creazione\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 108,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Canada Goose",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 109,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DIESEL",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 110,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AQC_Leather",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 111,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BEAUMANOIR (CC-Mor-Bon-Breal)",
|
||||||
|
"Descrizione": "04\/02\/21_ AGGIORNATO 05\/08\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 112,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BooHoo",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 114,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Golden Goose",
|
||||||
|
"Descrizione": "Golden goose\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 115,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ZLABEL",
|
||||||
|
"Descrizione": "Schema per ZLABEL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 116,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Zadig & Voltaire",
|
||||||
|
"Descrizione": "Schema per Zadig & Voltaire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 117,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Gemo",
|
||||||
|
"Descrizione": "Schema solo per Gemo\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 118,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PROMOD",
|
||||||
|
"Descrizione": "CHF 06\/08\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 119,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LA HALLE (BEAUMANOIR)",
|
||||||
|
"Descrizione": "13\/08\/2021 CHF\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 120,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LA REDOUTE",
|
||||||
|
"Descrizione": "14\/09\/2021 AD\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 121,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TOD'S",
|
||||||
|
"Descrizione": "Schema per materiale gb18401 e GB20400\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 122,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ASOS rev 1",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 123,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Monoprix",
|
||||||
|
"Descrizione": "Schema per Monoprix\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 124,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DIOR Ita",
|
||||||
|
"Descrizione": "CHF 21\/03\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 125,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GEOX - Raw Material",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER GEOX - SOLO PER LE SUOLE E MATERIALI DENOMINATI RPU \/ RAW MATERIAL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 126,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CAMAIEU",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER CAMAIEU\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 127,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Golden Goose FTW",
|
||||||
|
"Descrizione": "Golden goose\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 128,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "STEVE MADDEN - FOOTWEAR",
|
||||||
|
"Descrizione": "DA UTILIZZARE SOLO PER DESTINAZIONE D'USO CALZATURA\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 129,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Carhartt",
|
||||||
|
"Descrizione": "SCHEMA DA UTILIZZARE SOLO PER RICHIESTE UFFICIALI CARHARTT\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 131,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DAMART",
|
||||||
|
"Descrizione": "\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 132,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Gruppo OTB",
|
||||||
|
"Descrizione": "Schema per Staff International, Diesel e Brave kid\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 133,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FERRARI",
|
||||||
|
"Descrizione": "Schema da usare per Ferrari e fornitori\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 134,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GAP - ABBIGLIAMENTO",
|
||||||
|
"Descrizione": "Schema GAP da utilizzare solo per destinazione abbigliamento\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 135,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GAP - CALZATURA",
|
||||||
|
"Descrizione": "Schema GAP da utilizzare solo per destinazione calzatura\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 136,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "SALLING GROUP",
|
||||||
|
"Descrizione": "Schema per Salling Group\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 137,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "SOFT SURROUNDINGS",
|
||||||
|
"Descrizione": "Schema da utilizzare per Soft Surroundings\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 138,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "E-LIMS - Cuoio\/Pelle Standard \/ Leather",
|
||||||
|
"Descrizione": "Schema da utilizzare solo per accettazioni online\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 139,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ZALANDO",
|
||||||
|
"Descrizione": "Schema per ZALANDO ------ (NON per ZLABEL che ha il suo)\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 140,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LVMH",
|
||||||
|
"Descrizione": "gennaio 2023\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 141,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Valentino - eLims",
|
||||||
|
"Descrizione": "SCHEMA DA UTILIZZARE SOLO PER L'ACCETTAZIONE ONLINE DI VALENTINO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 142,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FENDI PELLETTERIA COMPLIANCE",
|
||||||
|
"Descrizione": "Solo per FENDI Pelletteria_INGLESE 04\/05\/2023\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 143,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TAPESTRY",
|
||||||
|
"Descrizione": "04\/05\/2023, agg secondo procedura 08\/11\/23\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 144,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ALEXANDER MC QUEEN",
|
||||||
|
"Descrizione": "ALEXANDER MC QUEEN 15\/05\/2023\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 145,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes_Chimici_Parigi",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 146,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CELINE ABBIGLIAMENTO_Progetto Speciale",
|
||||||
|
"Descrizione": "IO 202 CELINE ABBIGLIAMENTO_06\/06\/203_CHF\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 147,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GEOX - Prodotto Finito",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER GEOX - SOLO PER PRODOTTO FINITO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 149,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes\/IDO",
|
||||||
|
"Descrizione": "creato il 05\/07\/2023 CHF\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 150,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Tessile \/ Textiles PER CLIENTI CON OBLO",
|
||||||
|
"Descrizione": "Schema per tutti i Tessuti QUANDO IL CLIENTE NECESSITA DI NR OBLO\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 151,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "J JIll",
|
||||||
|
"Descrizione": "Schema per cliente J JIll, necessario riportare la recommended fiber content in schema verde\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 152,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AUCHAN - TAPE A L'OEIL",
|
||||||
|
"Descrizione": "Schema AUCHAN da utilizzare solo per la divisione TAPE A L'OEIL SA, successivamente se uguale da usare anche per le altre divisioni ed uniformarlo come generico"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 153,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ALL SAINTS - BUSCEMI",
|
||||||
|
"Descrizione": "SCHE DA USARE SOLO PER ALL SAINTS E BUSCEMI\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 154,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CELINE - LVMH",
|
||||||
|
"Descrizione": "Schema con aggiunta campi LVMH per estrazioni\r\nAD-29\/03\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 155,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "SeyMeChamLou",
|
||||||
|
"Descrizione": "DA USARE SOLO PER SEYMECHAMLOU (LOUBOUTIN)\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 156,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PRADA",
|
||||||
|
"Descrizione": "PER ADESSO DA USARE PER ABBIGLIAMENTO E CALZATURA\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 157,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes_HCP",
|
||||||
|
"Descrizione": "Schema per unicamente HCP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 158,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "STONE ISLAND",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 159,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel_Pierre Damien",
|
||||||
|
"Descrizione": "Schema da usare per Campioni ricevuti da Pierre-Damien Verine e suo staff CHANEL.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 160,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ACNE",
|
||||||
|
"Descrizione": "\r\n.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 161,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "OBERALP GROUP",
|
||||||
|
"Descrizione": "Schema da usare solo per Oberalp Group\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 162,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Club Monaco",
|
||||||
|
"Descrizione": "da usare solo per Club Monaco GR 20\/02\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 163,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Devred",
|
||||||
|
"Descrizione": "Schema creato per cliente DEVRED\r\nGR 18\/03\/2024\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 164,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "MONCLER Supplier",
|
||||||
|
"Descrizione": "Da utilizzare per fornitori Moncler \r\nGR 19\/03\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 165,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Kering Sunglasses",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 166,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Giorgio Armani",
|
||||||
|
"Descrizione": "\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 167,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel USA",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 168,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Staff Calzatura",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 169,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "P&G SRL",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 170,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "INCOM",
|
||||||
|
"Descrizione": "Schema da utilizzare per INCOM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 171,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "RIVER ISLAND",
|
||||||
|
"Descrizione": "SCHEDA DA USARE SOLO PER RIVER ISLAND - NO CALZATURA\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 172,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Longchamp",
|
||||||
|
"Descrizione": "Schema per tutti i campioni con RIchiesta Longchamp ufficiale\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 173,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Bottega Veneta",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di Bottega Veneta di Stella"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 174,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Mint Velvet",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di Mint Velvel con richiesta ufficiale.\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 176,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "RIVER ISLAND FOOTWEAR",
|
||||||
|
"Descrizione": "SCHEDA DA USARE SOLO PER RIVER ISLAND - USARE SOLO PER\r\n CALZATURA\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 177,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Phoebe philo ACC",
|
||||||
|
"Descrizione": "(scarpe, borse, cinture, occhiali, gioielleria)\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 178,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "New Guards Group",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 179,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Giorgio Armani Operation",
|
||||||
|
"Descrizione": "\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 180,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chloe'",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 181,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LVMH non diretti",
|
||||||
|
"Descrizione": "utilizzato ogni qualvolta siano caricati pacchetti \/ prove singole che non rientrano nel programma LVMH \r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 182,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Ralph Lauren - All testing V.6",
|
||||||
|
"Descrizione": "AGGIORNAMENTO AL 16\/03\/2026 per estrazione fatturazione"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 183,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TWINSET",
|
||||||
|
"Descrizione": "Schema da usare per Twinset - come da mail di EP del 20\/05\/2025\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 184,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ACNE STUDIOS rev 01",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 185,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Brunello cucinelli",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 186,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TWINSET",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 187,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LORO PIANA",
|
||||||
|
"Descrizione": "Schema per tutti i campioni Loro Piana\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 188,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LEMAIRE",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 189,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TEST_IT_SCHEMA",
|
||||||
|
"Descrizione": "Test per IT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 190,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LBS Interscambio",
|
||||||
|
"Descrizione": "Schema per tutti i campioni interscambio LBS\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 191,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "KIABI",
|
||||||
|
"Descrizione": "Schema per il cliente Kiabi\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 192,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "INDITEX",
|
||||||
|
"Descrizione": "Schema da usare solo per richieste INDITEX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 193,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AQC_Other materials",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 194,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes ADM & Silk",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER LA DIVISIONE ADM & SILK\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 195,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chloe'_APPAREL",
|
||||||
|
"Descrizione": "Schema aggiornato il 18\/12\/25 secondo modulo excel x codifica Elims\r\nGR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 196,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DUNHILL_DRAFT NON USARE",
|
||||||
|
"Descrizione": "SCHEMA DUNHILL NON USARE STUDIO NUOVA PROCEDURA NOVEMBRE 2025\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 197,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BERLUTI - LVMH",
|
||||||
|
"Descrizione": "Creato per accettazione Elims\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 198,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PIAGET (gruppo Cartier)",
|
||||||
|
"Descrizione": "Schema per tutti i campioni PIAGET (gruppo Cartier)\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 199,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "HERMES PAP FEMME",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di HERMES PAP FEMME \r\n15\/01\/2025\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 200,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CARHARTT ( provvisiorio in revisione)",
|
||||||
|
"Descrizione": "Schema per tutti i campioni CARHARTT provvissorio\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 201,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ROSSIMODA",
|
||||||
|
"Descrizione": "Per tutti i campioni di ROSSIMODA\r\n\r\n"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,56 @@
|
|||||||
input:checked+.slider:before {
|
input:checked+.slider:before {
|
||||||
transform: translateX(14px);
|
transform: translateX(14px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-source {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0.30rem 0.55rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-source-xls {
|
||||||
|
background-color: #e7f1ff;
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-source-api {
|
||||||
|
background-color: #e8fff1;
|
||||||
|
color: #198754;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable th,
|
||||||
|
#xlsTemplatesTable td {
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xlsTemplatesTable td.description-cell,
|
||||||
|
#xlsTemplatesTable td.client-cell,
|
||||||
|
#xlsTemplatesTable td.name-cell,
|
||||||
|
#xlsTemplatesTable td.button-cell {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-actions .btn {
|
||||||
|
padding: 0.25rem 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-card .card-body {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -65,18 +115,20 @@
|
|||||||
<!--sidebar wrapper -->
|
<!--sidebar wrapper -->
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<!--end sidebar wrapper -->
|
<!--end sidebar wrapper -->
|
||||||
|
|
||||||
<!--start header -->
|
<!--start header -->
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
<!--end header -->
|
<!--end header -->
|
||||||
|
|
||||||
<!--start page wrapper -->
|
<!--start page wrapper -->
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<?php include('top_stat_widget.php'); ?>
|
<?php include('top_stat_widget.php'); ?>
|
||||||
|
|
||||||
<div class="card radius-10">
|
<div class="card radius-10 compact-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<h6 class="mb-0">XLS Templates Dashboard</h6>
|
<h6 class="mb-0">Templates Dashboard</h6>
|
||||||
<a href="insert_template_xls.php" class="btn btn-success ms-auto">
|
<a href="insert_template_xls.php" class="btn btn-success ms-auto">
|
||||||
<i class="fas fa-plus"></i> New Template
|
<i class="fas fa-plus"></i> New Template
|
||||||
</a>
|
</a>
|
||||||
@@ -85,22 +137,22 @@
|
|||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="xlsTemplatesTable" class="table table-striped table-bordered">
|
<table id="xlsTemplatesTable" class="table table-striped table-bordered table-sm w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
|
||||||
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th>Client Name</th>
|
|
||||||
<th>Button Label</th>
|
|
||||||
<th>Status</th> <!-- Aggiunta colonna Status -->
|
|
||||||
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Row</th>
|
||||||
|
<th>Col</th>
|
||||||
|
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Button</th>
|
||||||
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<!-- DataTables riempirà questa sezione automaticamente -->
|
<!-- DataTables will populate this section automatically -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -110,25 +162,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end page wrapper -->
|
<!--end page wrapper -->
|
||||||
|
|
||||||
<!--start overlay-->
|
<!--start overlay-->
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<!--end overlay-->
|
<!--end overlay-->
|
||||||
|
|
||||||
<!--Start Back To Top Button-->
|
<!--Start Back To Top Button-->
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<!--End Back To Top Button-->
|
<!--End Back To Top Button-->
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
<!--end wrapper-->
|
<!--end wrapper-->
|
||||||
|
|
||||||
<!-- search modal -->
|
|
||||||
<?php //include('include/searchmodal.php');
|
|
||||||
?>
|
|
||||||
<!-- end search modal -->
|
|
||||||
|
|
||||||
<!--start switcher-->
|
|
||||||
<?php //include('include/themeswitcher.php');
|
|
||||||
?>
|
|
||||||
<!--end switcher-->
|
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
||||||
@@ -139,47 +185,92 @@
|
|||||||
processing: true,
|
processing: true,
|
||||||
serverSide: false,
|
serverSide: false,
|
||||||
ajax: 'load_templates.php',
|
ajax: 'load_templates.php',
|
||||||
|
pageLength: 50,
|
||||||
|
autoWidth: false,
|
||||||
columns: [{
|
columns: [{
|
||||||
data: 'id', // ID del template
|
data: 'id',
|
||||||
title: "ID"
|
orderable: false,
|
||||||
},
|
searchable: false,
|
||||||
{
|
title: "Actions",
|
||||||
data: 'name', // Nome del template
|
className: "table-actions text-center",
|
||||||
title: "Template Name"
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
data: 'header_row', // Riga degli header
|
|
||||||
title: "Header Row"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'start_column', // Colonna di partenza
|
|
||||||
title: "Start Column"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'description', // Descrizione del template
|
|
||||||
title: "Description",
|
|
||||||
defaultContent: 'No description'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: null, // Nuova colonna per Client Name e ID
|
|
||||||
title: "Client Name",
|
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
const clientName = row.clientname || "No client";
|
return `
|
||||||
const clientId = row.idclient || "N/A";
|
<div class="d-flex justify-content-center gap-1">
|
||||||
return `${clientName} (ID: ${clientId})`;
|
<a href="edit_template_xls.php?id=${data}" class="btn btn-sm btn-primary" title="Edit">
|
||||||
|
<i class="bx bx-edit-alt"></i>
|
||||||
|
</a>
|
||||||
|
<a href="mapping_template_xls_scheme2.php?id=${data}" class="btn btn-sm btn-success" title="Mapping">
|
||||||
|
<i class="bx bx-link-alt"></i>
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${data})" title="Delete">
|
||||||
|
<i class="bx bx-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'button_label', // Nuova colonna per Button Label
|
data: 'name',
|
||||||
title: "Button Label",
|
title: "Template Name",
|
||||||
|
className: "name-cell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'source_type',
|
||||||
|
title: "Type",
|
||||||
|
className: "text-center",
|
||||||
|
render: function(data, type, row) {
|
||||||
|
const sourceType = (data || 'XLS').toUpperCase();
|
||||||
|
|
||||||
|
if (type === 'display') {
|
||||||
|
if (sourceType === 'API') {
|
||||||
|
return '<span class="badge-source badge-source-api">API</span>';
|
||||||
|
}
|
||||||
|
return '<span class="badge-source badge-source-xls">XLS</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceType;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'header_row',
|
||||||
|
title: "Row",
|
||||||
|
className: "text-center",
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'start_column',
|
||||||
|
title: "Col",
|
||||||
|
className: "text-center",
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'description',
|
||||||
|
title: "Description",
|
||||||
|
className: "description-cell",
|
||||||
|
defaultContent: 'No description'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
title: "Client",
|
||||||
|
className: "client-cell",
|
||||||
|
render: function(data, type, row) {
|
||||||
|
const clientName = row.clientname || "No client";
|
||||||
|
const clientId = row.idclient || "N/A";
|
||||||
|
return `${clientName} <small class="text-muted">(ID: ${clientId})</small>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'button_label',
|
||||||
|
title: "Button",
|
||||||
|
className: "button-cell",
|
||||||
defaultContent: 'Click Me'
|
defaultContent: 'Click Me'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'status', // Stato con Toggle Switch
|
data: 'status',
|
||||||
title: "Status",
|
title: "Status",
|
||||||
orderable: false,
|
orderable: false,
|
||||||
searchable: false,
|
searchable: false,
|
||||||
|
className: "text-center",
|
||||||
render: function(status, type, row) {
|
render: function(status, type, row) {
|
||||||
let checked = (status === "active") ? "checked" : "";
|
let checked = (status === "active") ? "checked" : "";
|
||||||
return `
|
return `
|
||||||
@@ -189,31 +280,13 @@
|
|||||||
</label>
|
</label>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
data: 'id', // Azioni: Modifica, Mappatura e Eliminazione
|
|
||||||
orderable: false,
|
|
||||||
searchable: false,
|
|
||||||
title: "Actions",
|
|
||||||
render: function(data) {
|
|
||||||
return `
|
|
||||||
<div class="d-flex">
|
|
||||||
<a href="edit_template_xls.php?id=${data}" class="btn btn-sm btn-primary me-1">
|
|
||||||
<i class="bx bx-edit-alt"></i>
|
|
||||||
</a>
|
|
||||||
<a href="mapping_template_xls_scheme2.php?id=${data}" class="btn btn-sm btn-success me-1">
|
|
||||||
<i class="bx bx-link-alt"></i>
|
|
||||||
</a>
|
|
||||||
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${data})">
|
|
||||||
<i class="bx bx-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
dom: '<"card-header border-bottom p-3"<"d-flex align-items-center"<"card-title mb-0 flex-grow-1"f>>>rt<"card-footer border-top p-3"<"d-flex align-items-center"<"me-auto"l><"d-flex gap-2"ip>>>',
|
dom: '<"card-header border-bottom p-3"<"d-flex align-items-center"<"card-title mb-0 flex-grow-1"f>>>rt<"card-footer border-top p-3"<"d-flex align-items-center"<"me-auto"l><"d-flex gap-2"ip>>>',
|
||||||
lengthMenu: [10, 25, 50, 100],
|
lengthMenu: [10, 25, 50, 100],
|
||||||
|
order: [
|
||||||
|
[1, 'asc']
|
||||||
|
],
|
||||||
language: {
|
language: {
|
||||||
search: "Cerca:",
|
search: "Cerca:",
|
||||||
lengthMenu: "Mostra _MENU_ elementi",
|
lengthMenu: "Mostra _MENU_ elementi",
|
||||||
@@ -252,20 +325,21 @@
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: "update_template_status.php",
|
url: "update_template_status.php",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
data: {
|
data: {
|
||||||
id: templateId,
|
id: templateId,
|
||||||
status: newStatus
|
status: newStatus
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
console.log("✅ Status updated successfully.");
|
console.log("Status updated successfully.");
|
||||||
} else {
|
} else {
|
||||||
console.error("❌ Error updating status:", response.message);
|
console.error("Error updating status:", response.message);
|
||||||
alert("Error updating status: " + response.message);
|
alert("Error updating status: " + response.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function(xhr) {
|
||||||
console.error("❌ AJAX error.");
|
console.error("AJAX error:", xhr.responseText);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,47 +6,88 @@ if (!Auth::check()) {
|
|||||||
redirectTo('../public/login');
|
redirectTo('../public/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = Auth::user();
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
$id = $_POST['iduserlogin'];
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$first_name = $_POST['first_name'];
|
|
||||||
$last_name = $_POST['last_name'];
|
|
||||||
$email = $_POST['email'];
|
|
||||||
$password = $_POST['password'] ?: null;
|
|
||||||
|
|
||||||
$db = DBHandlerSelect::getInstance()->getConnection();
|
|
||||||
|
|
||||||
// Gestione avatar
|
|
||||||
$avatar = $user->present()->avatar;
|
|
||||||
if (isset($_FILES['avatar']) && $_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
|
|
||||||
$avatar = time() . '_' . basename($_FILES['avatar']['name']);
|
|
||||||
$uploadDir = __DIR__ . '/../../public/upload/users/';
|
|
||||||
if (!is_dir($uploadDir)) {
|
|
||||||
mkdir($uploadDir, 0755, true);
|
|
||||||
}
|
|
||||||
move_uploaded_file($_FILES['avatar']['tmp_name'], $uploadDir . $avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aggiornamento dati
|
|
||||||
$sql = "UPDATE auth_users SET first_name = ?, last_name = ?, email = ?, avatar = ? WHERE id = ?";
|
|
||||||
$stmt = $db->prepare($sql);
|
|
||||||
$stmt->execute([$first_name, $last_name, $email, $avatar, $id]);
|
|
||||||
|
|
||||||
// Aggiornamento password se fornita
|
|
||||||
if ($password) {
|
|
||||||
$hashedPassword = password_hash($password, PASSWORD_BCRYPT);
|
|
||||||
$sql = "UPDATE auth_users SET password = ? WHERE id = ?";
|
|
||||||
$stmt = $db->prepare($sql);
|
|
||||||
$stmt->execute([$hashedPassword, $id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aggiorna la sessione con i nuovi dati
|
|
||||||
$_SESSION["nameuser"] = $first_name;
|
|
||||||
$_SESSION["surnameuser"] = $last_name;
|
|
||||||
$_SESSION["emailuser"] = $email;
|
|
||||||
$_SESSION["photouser"] = $avatar;
|
|
||||||
|
|
||||||
header('Location: user-profile.php');
|
header('Location: user-profile.php');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$user = Auth::user();
|
||||||
|
$id = isset($_POST['iduserlogin']) ? (int)$_POST['iduserlogin'] : 0;
|
||||||
|
|
||||||
|
$first_name = trim($_POST['first_name'] ?? '');
|
||||||
|
$last_name = trim($_POST['last_name'] ?? '');
|
||||||
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
$password = trim($_POST['password'] ?? '');
|
||||||
|
|
||||||
|
$lims_user_id = isset($_POST['lims_user_id']) && $_POST['lims_user_id'] !== ''
|
||||||
|
? (int)$_POST['lims_user_id']
|
||||||
|
: null;
|
||||||
|
|
||||||
|
$lims_global_user_id = isset($_POST['lims_global_user_id']) && $_POST['lims_global_user_id'] !== ''
|
||||||
|
? (int)$_POST['lims_global_user_id']
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
die('Invalid user ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
|
// Current avatar
|
||||||
|
$avatar = $user->present()->avatar;
|
||||||
|
|
||||||
|
// Avatar upload
|
||||||
|
if (isset($_FILES['avatar']) && $_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
|
||||||
|
$originalName = basename($_FILES['avatar']['name']);
|
||||||
|
$safeName = preg_replace('/[^A-Za-z0-9_\.-]/', '_', $originalName);
|
||||||
|
$avatar = time() . '_' . $safeName;
|
||||||
|
|
||||||
|
$uploadDir = __DIR__ . '/../../public/upload/users/';
|
||||||
|
if (!is_dir($uploadDir)) {
|
||||||
|
mkdir($uploadDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_uploaded_file($_FILES['avatar']['tmp_name'], $uploadDir . $avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update main user data
|
||||||
|
$sql = "UPDATE auth_users
|
||||||
|
SET first_name = ?,
|
||||||
|
last_name = ?,
|
||||||
|
email = ?,
|
||||||
|
avatar = ?,
|
||||||
|
lims_user_id = ?,
|
||||||
|
lims_global_user_id = ?
|
||||||
|
WHERE id = ?";
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
$stmt->execute([
|
||||||
|
$first_name,
|
||||||
|
$last_name,
|
||||||
|
$email,
|
||||||
|
$avatar,
|
||||||
|
$lims_user_id,
|
||||||
|
$lims_global_user_id,
|
||||||
|
$id
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update password only if provided
|
||||||
|
if ($password !== '') {
|
||||||
|
$hashedPassword = password_hash($password, PASSWORD_BCRYPT);
|
||||||
|
|
||||||
|
$sql = "UPDATE auth_users SET password = ? WHERE id = ?";
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
$stmt->execute([$hashedPassword, $id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update session
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION["nameuser"] = $first_name;
|
||||||
|
$_SESSION["surnameuser"] = $last_name;
|
||||||
|
$_SESSION["emailuser"] = $email;
|
||||||
|
$_SESSION["photouser"] = $avatar;
|
||||||
|
|
||||||
|
header('Location: user-profile.php');
|
||||||
|
exit;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
require_once(__DIR__ . '/include/headscript.php');
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$id = (int)($input['id'] ?? 0);
|
||||||
|
$field = (string)($input['field'] ?? '');
|
||||||
|
$value = $input['value'] ?? null;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid id']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed = ['default_value', 'is_visible_import', 'is_required'];
|
||||||
|
if (!in_array($field, $allowed, true)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid field']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($field === 'is_visible_import' || $field === 'is_required') {
|
||||||
|
$value = ((int)$value === 1) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$sql = "UPDATE template_fixed_mapping SET {$field} = :val WHERE id = :id";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$ok = $stmt->execute([':val' => $value, ':id' => $id]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => (bool)$ok]);
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
throw new Exception('Metodo non valido');
|
||||||
|
}
|
||||||
|
|
||||||
|
$photoId = isset($_POST['photo_id']) ? (int)$_POST['photo_id'] : 0;
|
||||||
|
$field = isset($_POST['field']) ? trim($_POST['field']) : '';
|
||||||
|
$value = isset($_POST['value']) ? (int)$_POST['value'] : 0;
|
||||||
|
|
||||||
|
if ($photoId <= 0) {
|
||||||
|
throw new Exception('photo_id mancante o non valido');
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedFields = ['StampaNelRapporto', 'PrimaPagina'];
|
||||||
|
if (!in_array($field, $allowedFields, true)) {
|
||||||
|
throw new Exception('Campo non consentito');
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $value === 1 ? 1 : 0;
|
||||||
|
|
||||||
|
// Recupera la foto per sapere a quale record padre appartiene
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT id, iddatadb, idquotations
|
||||||
|
FROM datadb_photos
|
||||||
|
WHERE id = ?
|
||||||
|
LIMIT 1
|
||||||
|
");
|
||||||
|
$stmt->execute([$photoId]);
|
||||||
|
$photo = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$photo) {
|
||||||
|
throw new Exception('Foto non trovata');
|
||||||
|
}
|
||||||
|
|
||||||
|
$iddatadb = !empty($photo['iddatadb']) ? (int)$photo['iddatadb'] : null;
|
||||||
|
$idquotations = !empty($photo['idquotations']) ? (int)$photo['idquotations'] : null;
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
if ($field === 'PrimaPagina' && $value === 1) {
|
||||||
|
// Solo una foto può essere PrimaPagina per lo stesso record padre
|
||||||
|
if ($iddatadb) {
|
||||||
|
$stmtReset = $pdo->prepare("
|
||||||
|
UPDATE datadb_photos
|
||||||
|
SET PrimaPagina = 0
|
||||||
|
WHERE iddatadb = ?
|
||||||
|
");
|
||||||
|
$stmtReset->execute([$iddatadb]);
|
||||||
|
} elseif ($idquotations) {
|
||||||
|
$stmtReset = $pdo->prepare("
|
||||||
|
UPDATE datadb_photos
|
||||||
|
SET PrimaPagina = 0
|
||||||
|
WHERE idquotations = ?
|
||||||
|
");
|
||||||
|
$stmtReset->execute([$idquotations]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmtUpdate = $pdo->prepare("
|
||||||
|
UPDATE datadb_photos
|
||||||
|
SET {$field} = ?
|
||||||
|
WHERE id = ?
|
||||||
|
");
|
||||||
|
$stmtUpdate->execute([$value, $photoId]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'photo_id' => $photoId,
|
||||||
|
'field' => $field,
|
||||||
|
'value' => $value
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if (isset($pdo) && $pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'include/headscript.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$template_id = isset($data['template_id']) ? (int)$data['template_id'] : 0;
|
||||||
|
$mapping_id = isset($data['mapping_id']) ? (int)$data['mapping_id'] : 0;
|
||||||
|
$value = isset($data['value']) ? (int)$data['value'] : null;
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if ($template_id <= 0 || $mapping_id <= 0 || $value === null) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid input']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize to 0/1
|
||||||
|
$value = ($value === 1) ? 1 : 0;
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
if ($value === 1) {
|
||||||
|
// 1) Force ONLY ONE row visible_parts per template:
|
||||||
|
// set all to 0 for this template
|
||||||
|
$stmtReset = $pdo->prepare("
|
||||||
|
UPDATE template_mapping
|
||||||
|
SET is_visible_parts = 0
|
||||||
|
WHERE template_id = ?
|
||||||
|
");
|
||||||
|
$stmtReset->execute([$template_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Set requested mapping to 1 or 0
|
||||||
|
$stmtSet = $pdo->prepare("
|
||||||
|
UPDATE template_mapping
|
||||||
|
SET is_visible_parts = ?
|
||||||
|
WHERE id = ? AND template_id = ?
|
||||||
|
");
|
||||||
|
$stmtSet->execute([$value, $mapping_id, $template_id]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'template_id' => $template_id,
|
||||||
|
'mapping_id' => $mapping_id,
|
||||||
|
'value' => $value
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -48,6 +48,17 @@
|
|||||||
<label for="email" class="form-label">Email</label>
|
<label for="email" class="form-label">Email</label>
|
||||||
<input type="email" class="form-control" id="email" name="email" value="<?= htmlspecialchars($emailuser); ?>" required>
|
<input type="email" class="form-control" id="email" name="email" value="<?= htmlspecialchars($emailuser); ?>" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="lims_user_id" class="form-label">Accettatore</label>
|
||||||
|
<input type="number" class="form-control" id="lims_user_id" name="lims_user_id" value="<?= htmlspecialchars($lims_user_id ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="lims_global_user_id" class="form-label">LIMS Global</label>
|
||||||
|
<input type="number" class="form-control" id="lims_global_user_id" name="lims_global_user_id" value="<?= htmlspecialchars($lims_global_user_id ?? ''); ?>">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="avatar" class="form-label">Profile Picture</label>
|
<label for="avatar" class="form-label">Profile Picture</label>
|
||||||
<input type="file" class="form-control" id="avatar" name="avatar">
|
<input type="file" class="form-control" id="avatar" name="avatar">
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
<?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 [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── 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) for fixed field validation
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT iddatadb, consegna_richiesta
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Run validators per row ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
foreach ($rows as $rowInfo) {
|
||||||
|
$iddatadb = (int)$rowInfo['iddatadb'];
|
||||||
|
$index = $rowInfo['index'];
|
||||||
|
|
||||||
|
// Build context for validators
|
||||||
|
$ctx = [
|
||||||
|
'record' => $recordsInfo[$iddatadb] ?? null,
|
||||||
|
'parts' => $partsInfo[$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()]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user