Compare commits

..

19 Commits

Author SHA1 Message Date
RMubarakzyanov e3994d6f9f fix notices running on php-8.2 2026-02-26 22:59:41 +03:00
solocla 9af0df3cca env example update 2026-02-26 17:14:16 +01:00
solocla 48d2a3ff42 time and date setting 2026-02-25 22:07:44 +01:00
solocla cf44e67922 added auto user accettatore id 2026-02-25 15:24:41 +01:00
solocla 35021e9d9b dropdown in alphabetical order 2026-02-25 10:02:45 +01:00
solocla 497ebda65a update gitignore 2026-02-24 09:09:32 +01:00
solocla b0024edb70 mapping fixed 2026-02-24 09:06:45 +01:00
solocla b9852ba226 saved rows 2026-02-19 12:07:32 +01:00
solocla 407d6884a1 fixed note save and import special character 2026-02-19 11:55:24 +01:00
solocla 1a4beadbb2 fixed propagate dropdown 2026-02-18 11:52:26 +01:00
solocla 4bb0445cff added select 2 on all fields (with limit of 12) 2026-02-18 10:48:04 +01:00
solocla 73dd8f4ce8 fixed column size final 2026-02-18 10:04:27 +01:00
solocla bdc4e0e60c fixed size column 2026-02-18 09:58:42 +01:00
solocla ef8f2d8000 fixed labels 2026-02-18 09:54:21 +01:00
solocla 74c9a1d02a added time field 2026-02-18 09:34:26 +01:00
solocla cd3bccd183 added multiple tested components 2026-02-17 09:04:30 +01:00
solocla 78154e43a9 fixed tested components 2026-02-05 10:32:28 +01:00
solocla 9fe9243e60 fixed mapping template 2026-02-05 09:05:51 +01:00
solocla a8330d4aba fixed layout 2026-02-04 15:31:53 +01:00
18 changed files with 1371 additions and 249 deletions
+7 -18
View File
@@ -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"
+32 -43
View File
@@ -1,66 +1,55 @@
.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/error_log.txt
/public/userarea/import_debug.log
/public/userarea/last_url.txt
/public/userarea/logaspi/
/public/userarea/logsapi/
/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
+91
View File
@@ -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;
File diff suppressed because one or more lines are too long
+285
View File
@@ -27,3 +27,288 @@
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 [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 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-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"}
+1 -1
View File
@@ -13,7 +13,7 @@ try {
// Parametri OData // Parametri OData
$params = [ $params = [
'$select' => 'IdCliente,Nominativo,CodiceNazioneFatturazione', '$select' => 'IdCliente,Nominativo,CodiceCliente',
'$orderby' => 'Nominativo asc' '$orderby' => 'Nominativo asc'
]; ];
+17 -3
View File
@@ -15,17 +15,31 @@ try {
$endpoint = 'MoltiplicatorePrezzi'; $endpoint = 'MoltiplicatorePrezzi';
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.) // Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
$options = []; // es: ['$top' => 100] $options = [
'$orderby' => 'Descrizione asc'
];
// Debug: salva URL usata // Debug: salva URL usata
$base_url = 'https://93.43.5.102/limsapi/api/odata/'; $base_url = 'https://93.43.5.102/limsapi/api/odata/';
$query = http_build_query($options); $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 : ''); $full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND); file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
// Chiamata API // Chiamata API
$data = $api->get($endpoint, $options); $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 // Salva il JSON in locale
file_put_contents(__DIR__ . '/moltiplicatori_prezzo_response.json', json_encode($data, JSON_PRETTY_PRINT)); file_put_contents(__DIR__ . '/moltiplicatori_prezzo_response.json', json_encode($data, JSON_PRETTY_PRINT));
+2 -1
View File
@@ -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
+513 -120
View File
@@ -1,6 +1,10 @@
<?php <?php
include('include/headscript.php'); include('include/headscript.php');
// ✅ FIX timezone (Rome)
ini_set('date.timezone', 'Europe/Rome');
date_default_timezone_set('Europe/Rome');
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !isset($_POST['selected_rows']) || !isset($_POST['filename'])) { if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !isset($_POST['selected_rows']) || !isset($_POST['filename'])) {
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida")); header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
exit; exit;
@@ -22,10 +26,36 @@ $pdo = $db->getConnection();
$importReferenceCode = date('YmdHis') . '-' . uniqid(); $importReferenceCode = date('YmdHis') . '-' . uniqid();
// Recupera tutti i mapping dal template, includendo is_visible_import // Recupera tutti i mapping dal template, includendo is_visible_import
$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field, is_visible_import FROM template_mapping WHERE template_id = ?"); $stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field, is_visible_import, auto_value
FROM template_mapping
WHERE template_id = ?");
$stmt->execute([$template_id]); $stmt->execute([$template_id]);
$allMappings = $stmt->fetchAll(PDO::FETCH_ASSOC); $allMappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
$timeLabels = [
'Sample Arrival Time:',
'Sample Unlock Time:',
'Login Time:',
'Presa in carico, Orario:',
];
// Returns the auto value for current session (import) based on mapping.auto_value
function getImportAutoValue(array $mapping): string
{
$auto = $mapping['auto_value'] ?? 'none';
if ($auto === 'import_date') {
return date('Y-m-d');
}
if ($auto === 'import_time') {
// HTML <input type="time"> expects HH:MM (seconds optional)
return date('H:i');
}
return '';
}
if (empty($allMappings)) { if (empty($allMappings)) {
header("Location: import_xls.php?id=$template_id&status=error&message=" . urlencode("Nessun mapping trovato per il template")); header("Location: import_xls.php?id=$template_id&status=error&message=" . urlencode("Nessun mapping trovato per il template"));
exit; exit;
@@ -47,7 +77,52 @@ $template = $template_stmt->fetch(PDO::FETCH_ASSOC);
$default_idclient = $template['idclient'] ?? null; $default_idclient = $template['idclient'] ?? null;
$insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids']; $insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids'];
// ------------------------------------------------------------
// AUTO SET: schema field_id = 244 with auth_users.lims_user_id (if present)
// ------------------------------------------------------------
try {
// 1) Read logged user lims_user_id
$stmtUser = $pdo->prepare("SELECT lims_user_id FROM auth_users WHERE id = ? LIMIT 1");
$stmtUser->execute([(int)$user_id]);
$limsUserId = $stmtUser->fetchColumn();
// normalize
$limsUserId = ($limsUserId !== false && $limsUserId !== null && $limsUserId !== '') ? (string)$limsUserId : '';
if ($limsUserId !== '' && !empty($insertedIds)) {
// 2) Find mapping_id for field_id = 244 in this template
$stmtMap = $pdo->prepare("SELECT id FROM template_mapping WHERE template_id = ? AND field_id = 244 LIMIT 1");
$stmtMap->execute([(int)$template_id]);
$mappingId244 = (int)$stmtMap->fetchColumn();
if ($mappingId244 > 0) {
// 3) Upsert value into import_data_details for every inserted datadb row
$pdo->beginTransaction();
$updStmt = $pdo->prepare("UPDATE import_data_details SET field_value = ? WHERE id = ? AND mapping_id = ?");
$insStmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)");
foreach ($insertedIds as $iddatadb) {
$iddatadb = (int)$iddatadb;
if ($iddatadb <= 0) continue;
$updStmt->execute([$limsUserId, $iddatadb, $mappingId244]);
if ($updStmt->rowCount() === 0) {
$insStmt->execute([$iddatadb, $mappingId244, $limsUserId]);
}
}
$pdo->commit();
}
}
} catch (Exception $e) {
// Do not block import page if this fails; just log
error_log("[AUTO FIELD 244] " . $e->getMessage());
if ($pdo->inTransaction()) $pdo->rollBack();
}
// Recupera i dati appena inseriti con i nomi degli utenti // Recupera i dati appena inseriti con i nomi degli utenti
$stmt = $pdo->prepare(" $stmt = $pdo->prepare("
SELECT d.*, CONCAT(u.first_name, ' ', u.last_name) AS user_name SELECT d.*, CONCAT(u.first_name, ' ', u.last_name) AS user_name
@@ -60,7 +135,8 @@ $importedData = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Recupera i dettagli manuali da import_data_details // Recupera i dettagli manuali da import_data_details
$stmt = $pdo->prepare(" $stmt = $pdo->prepare("
SELECT d.id AS detail_id, d.id AS datadb_id, d.mapping_id, d.field_value, m.field_label, m.data_type, m.is_required, m.manual_default SELECT d.id AS detail_id, d.id AS datadb_id, d.mapping_id, d.field_value,
m.field_id, m.field_label, m.data_type, m.is_required, m.manual_default
FROM import_data_details d FROM import_data_details d
JOIN template_mapping m ON d.mapping_id = m.id JOIN template_mapping m ON d.mapping_id = m.id
WHERE d.id IN (" . implode(',', array_fill(0, count($insertedIds), '?')) . ") WHERE d.id IN (" . implode(',', array_fill(0, count($insertedIds), '?')) . ")
@@ -74,6 +150,9 @@ $slugMapping = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$slugMapping[$row['mysql_column_name']] = $row['user_friendly_slug']; $slugMapping[$row['mysql_column_name']] = $row['user_friendly_slug'];
} }
// --- FIX LABELS ONLY (do not change keys) ---
$slugMapping['AnagraficaCertestObject'] = 'Object';
$slugMapping['AnagraficaCertestService'] = 'Service';
// ---------------- FIXED FIELDS (from template_fixed_mapping) ---------------- // ---------------- FIXED FIELDS (from template_fixed_mapping) ----------------
$fixedStmt = $pdo->prepare(" $fixedStmt = $pdo->prepare("
@@ -155,6 +234,13 @@ function fixedDefaultValue(array $f): string
background-color: #f8d7da; background-color: #f8d7da;
} }
input.required-input,
select.required-input {
background-color: #f8d7da;
border-color: #ced4da !important;
box-shadow: none !important;
}
input, input,
select, select,
textarea { textarea {
@@ -278,8 +364,8 @@ function fixedDefaultValue(array $f): string
} }
/* Sticky columns - first column (Actions) */ /* Sticky columns - first column (Actions) */
.grid-top .grid-cell.save-all-cell, .grid-top .grid-cell.save-all-cell,
.grid-header.button-header, .grid-header.button-header,
.grid-cell.button-cell { .grid-cell.button-cell {
position: sticky !important; position: sticky !important;
left: 0; left: 0;
@@ -301,7 +387,7 @@ function fixedDefaultValue(array $f): string
background-color: #e9ecef; background-color: #e9ecef;
} }
.grid-top .grid-cell:nth-child(2), .grid-top .grid-cell:nth-child(2),
.grid-row .grid-header:nth-child(2), .grid-row .grid-header:nth-child(2),
.grid-row .grid-cell:nth-child(2) { .grid-row .grid-cell:nth-child(2) {
position: sticky !important; position: sticky !important;
@@ -323,7 +409,7 @@ function fixedDefaultValue(array $f): string
.grid-row:hover .grid-cell:nth-child(2) { .grid-row:hover .grid-cell:nth-child(2) {
background-color: #e9ecef; background-color: #e9ecef;
} }
.grid-row { .grid-row {
position: relative; position: relative;
} }
@@ -336,7 +422,7 @@ function fixedDefaultValue(array $f): string
background-color: #e0f7fa !important; background-color: #e0f7fa !important;
flex: 0 0 500px !important; flex: 0 0 500px !important;
} }
.grid-header.expanded { .grid-header.expanded {
background-color: #e0f7fa !important; background-color: #e0f7fa !important;
} }
@@ -482,11 +568,23 @@ function fixedDefaultValue(array $f): string
z-index: 1049; z-index: 1049;
} }
/* Required empty cell: keep light red background BUT NO red border */
.grid-cell.missing-required { .grid-cell.missing-required {
border: 2px solid red; background-color: #ffe6e6 !important;
background-color: #ffe6e6;
/* remove the red border you set */
border: 0 !important;
/* keep grid separators */
border-right: 1px solid #dee2e6 !important;
} }
/* if it is the last column, don't force the right border */
.grid-cell.missing-required:last-child {
border-right: none !important;
}
.dropdown-select { .dropdown-select {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
@@ -636,13 +734,11 @@ function fixedDefaultValue(array $f): string
<div class="card radius-10"> <div class="card radius-10">
<div class="card-header"> <div class="card-header">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div> <div id="unsavedChanges" style="display:none; color: red; font-weight: bold; margin:10px 0;">
<h6 class="mb-0">Modifica Dati Importati</h6> ⚠️ Unsaved changes detected! Please save before leaving this page.<br>
<div id="unsavedChanges" style="display:none; color: red; font-weight: bold; margin:10px 0;"> <span id="changedRows" style="font-weight:normal; color:darkred;"></span>
⚠️ Unsaved changes detected! Please save before leaving this page.
<ul id="changedFields" style="margin-top:5px; font-weight:normal; color:darkred;"></ul>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -711,7 +807,23 @@ function fixedDefaultValue(array $f): string
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex'><i class='fas fa-arrow-down'></i></button>"; echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex'><i class='fas fa-arrow-down'></i></button>";
echo "</div>"; echo "</div>";
} else { } else {
echo "<div class='grid-cell grid-top-cell' style='flex: 0 0 150px;' data-index='$topColIndex'></div>"; // Show auto import date/time in header too (read-only)
$autoVal = getImportAutoValue($mapping);
echo "<div class='grid-cell grid-top-cell' style='flex: 0 0 150px;' data-index='$topColIndex'>";
if (($mapping['auto_value'] ?? 'none') === 'import_date') {
echo "<input type='text' class='custom-field date-picker auto-input' value='" . htmlspecialchars($autoVal) . "' readonly>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex'><i class='fas fa-arrow-down'></i></button>";
} elseif (($mapping['auto_value'] ?? 'none') === 'import_time') {
echo "<input type='time' class='custom-field auto-input' value='" . htmlspecialchars($autoVal) . "' readonly>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex'><i class='fas fa-arrow-down'></i></button>";
} else {
// keep empty cell for other auto fields
echo "";
}
echo "</div>";
} }
$autoIndex++; $autoIndex++;
@@ -738,6 +850,8 @@ function fixedDefaultValue(array $f): string
echo "<input type='text' class='custom-field date-picker $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='text' class='custom-field date-picker $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') { } elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif (in_array($mapping['field_label'], $timeLabels)) {
echo "<input type='time' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
} else { } else {
echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
} }
@@ -748,8 +862,8 @@ function fixedDefaultValue(array $f): string
$topColIndex++; $topColIndex++;
} }
} }
echo "<div class='grid-cell grid-top-cell' style='flex: 0 0 150px;' data-index='$topColIndex'></div>"; echo "<div class='grid-cell grid-top-cell' style='flex: 0 0 150px;' data-index='$topColIndex'></div>";
$topColIndex++; $topColIndex++;
echo "<div class='grid-cell grid-top-cell' style='flex: 0 0 200px;' data-index='$topColIndex'></div>"; echo "<div class='grid-cell grid-top-cell' style='flex: 0 0 200px;' data-index='$topColIndex'></div>";
$topColIndex++; $topColIndex++;
@@ -952,6 +1066,14 @@ function fixedDefaultValue(array $f): string
$detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']); $detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']);
$detail = reset($detail) ?: ['field_value' => $mapping['manual_default']]; $detail = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? ''; $fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
// Auto-fill import date/time only if empty
if ($fieldValue === '' || $fieldValue === null) {
$autoVal = getImportAutoValue($mapping);
if ($autoVal !== '') {
$fieldValue = $autoVal;
}
}
$requiredClass = ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : ''; $requiredClass = ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : '';
$inputClass = 'auto-input'; $inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input'; if ($mapping['is_required']) $inputClass .= ' required-input';
@@ -964,6 +1086,10 @@ function fixedDefaultValue(array $f): string
echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input date-picker $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input date-picker $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') { } elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='number' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif (($mapping['auto_value'] ?? 'none') === 'import_time') {
echo "<input type='time' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif (in_array($mapping['field_label'], $timeLabels)) {
echo "<input type='time' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} else { } else {
echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} }
@@ -993,6 +1119,8 @@ function fixedDefaultValue(array $f): string
echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input date-picker $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input date-picker $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') { } elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='number' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} elseif (in_array($mapping['field_label'], $timeLabels)) {
echo "<input type='time' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} else { } else {
echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">"; echo "<input type='text' name='rows[$index][details][{$mapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mapping['is_required'] ? 'required' : '') . ">";
} }
@@ -1125,9 +1253,9 @@ function fixedDefaultValue(array $f): string
function expandColumn(cell, expand) { function expandColumn(cell, expand) {
const columnIndex = cell.getAttribute('data-index'); const columnIndex = cell.getAttribute('data-index');
if (!columnIndex) return; if (!columnIndex) return;
const allColumnCells = document.querySelectorAll(`.grid-cell[data-index="${columnIndex}"], .grid-header[data-index="${columnIndex}"], .grid-top-cell[data-index="${columnIndex}"]`); const allColumnCells = document.querySelectorAll(`.grid-cell[data-index="${columnIndex}"], .grid-header[data-index="${columnIndex}"], .grid-top-cell[data-index="${columnIndex}"]`);
allColumnCells.forEach(colCell => { allColumnCells.forEach(colCell => {
if (expand) { if (expand) {
colCell.classList.add('expanded'); colCell.classList.add('expanded');
@@ -1153,6 +1281,13 @@ function fixedDefaultValue(array $f): string
instance.input.dispatchEvent(event); instance.input.dispatchEvent(event);
} }
}); });
flatpickr(".time-picker", {
enableTime: true,
noCalendar: true,
dateFormat: "H:i",
time_24hr: true,
allowInput: true
});
}); });
$(document).on("click", ".export-lims-btn", function() { $(document).on("click", ".export-lims-btn", function() {
@@ -1185,52 +1320,49 @@ function fixedDefaultValue(array $f): string
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function() {
const inputs = document.querySelectorAll(".cell-input, .dropdown-select, .carrier-select, .awb-input, .date-picker"); const inputs = document.querySelectorAll(".cell-input, .dropdown-select, .carrier-select, .awb-input, .date-picker");
const unsavedDiv = document.getElementById("unsavedChanges"); const unsavedDiv = document.getElementById("unsavedChanges");
const changedList = document.getElementById("changedFields"); const changedRowsEl = document.getElementById("changedRows");
let hasChanges = false; let hasChanges = false;
let changedFields = {};
function renderChangedList() { // ✅ solo righe modificate (Set)
changedList.innerHTML = ""; let changedRows = new Set();
Object.keys(changedFields).forEach(rowIndex => {
const fields = changedFields[rowIndex]; function renderChangedRows() {
if (fields.length > 0) { const rows = Array.from(changedRows)
const li = document.createElement("li"); .map(n => Number(n))
li.textContent = `Row ${parseInt(rowIndex) + 1}: ${fields.join(", ")}`; .sort((a, b) => a - b);
changedList.appendChild(li);
} if (rows.length === 0) {
}); unsavedDiv.style.display = "none";
unsavedDiv.style.display = Object.keys(changedFields).length > 0 ? "block" : "none"; changedRowsEl.textContent = "";
return;
}
// Visuale: "Row 1, Row 5, Row 6"
changedRowsEl.textContent = rows.map(r => `Row ${r + 1}`).join(", ");
unsavedDiv.style.display = "block";
} }
inputs.forEach(el => { inputs.forEach(el => {
el.addEventListener("change", () => { el.addEventListener("change", () => {
hasChanges = true; hasChanges = true;
const gridCell = el.closest(".grid-cell"); const gridCell = el.closest(".grid-cell");
const colIndex = gridCell?.dataset.index;
const rowIndex = gridCell?.dataset.row; const rowIndex = gridCell?.dataset.row;
let label = "Unknown field";
if (colIndex) {
const header = document.querySelector(`.grid-header[data-index="${colIndex}"]`);
if (header) {
label = header.textContent.replace(":", "").trim();
}
}
// ✅ segnamo solo la riga
if (rowIndex !== undefined) { if (rowIndex !== undefined) {
if (!changedFields[rowIndex]) { changedRows.add(rowIndex);
changedFields[rowIndex] = [];
}
if (!changedFields[rowIndex].includes(label)) {
changedFields[rowIndex].push(label);
}
gridCell.classList.add("cell-changed");
} }
renderChangedList(); // (se vuoi mantenere highlight cella gialla, lascia questa riga)
if (gridCell) gridCell.classList.add("cell-changed");
renderChangedRows();
}); });
}); });
document.querySelectorAll(".save-btn").forEach(btn => { document.querySelectorAll(".save-btn").forEach(btn => {
btn.addEventListener("click", () => { btn.addEventListener("click", () => {
const rowIndex = btn.dataset.row; const rowIndex = btn.dataset.row;
@@ -1263,9 +1395,21 @@ function fixedDefaultValue(array $f): string
if (!inp.classList.contains('fixed-input')) return; if (!inp.classList.contains('fixed-input')) return;
const m = inp.name.match(/rows\[\d+\]\[([^\]]+)\]/); const m = inp.name.match(/rows\[\d+\]\[([^\]]+)\]/);
// Map: fixed key (logical) -> datadb real column
const fixedAliasMap = {
ClienteResponsabile: 'cliente_responsabile_id',
MoltiplicatorePrezzo: 'moltiplicatore_prezzo_id',
AnagraficaCertestObject: 'anagrafica_certest_object_id',
AnagraficaCertestService: 'anagrafica_certest_service_id',
ConsegnaRichiesta: 'consegna_richiesta'
};
if (m && m[1]) { if (m && m[1]) {
formData.append(m[1], inp.value); const logicalKey = m[1];
const realKey = fixedAliasMap[logicalKey] || logicalKey;
formData.append(realKey, inp.value);
} }
}); });
formData.append('iddatadb', iddatadb); formData.append('iddatadb', iddatadb);
@@ -1288,13 +1432,16 @@ function fixedDefaultValue(array $f): string
}); });
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500); setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
if (changedFields[rowIndex]) { // ✅ rimuovi riga dal set (non mostrare più Row X)
delete changedFields[rowIndex]; changedRows.delete(rowIndex);
document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`)
.forEach(cell => cell.classList.remove("cell-changed")); // se vuoi continuare a togliere highlight giallo di TUTTA la riga:
renderChangedList(); document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`)
hasChanges = Object.keys(changedFields).length > 0; .forEach(cell => cell.classList.remove("cell-changed"));
}
renderChangedRows();
hasChanges = changedRows.size > 0;
alert('Salvataggio riga avvenuto con successo!'); alert('Salvataggio riga avvenuto con successo!');
} else { } else {
@@ -1345,9 +1492,21 @@ function fixedDefaultValue(array $f): string
fixedInputs.forEach(inp => { fixedInputs.forEach(inp => {
if (!inp.classList.contains('fixed-input')) return; if (!inp.classList.contains('fixed-input')) return;
const m = inp.name.match(/rows\[\d+\]\[([^\]]+)\]/); const m = inp.name.match(/rows\[\d+\]\[([^\]]+)\]/);
// Map: fixed key (logical) -> datadb real column
const fixedAliasMap = {
ClienteResponsabile: 'cliente_responsabile_id',
MoltiplicatorePrezzo: 'moltiplicatore_prezzo_id',
AnagraficaCertestObject: 'anagrafica_certest_object_id',
AnagraficaCertestService: 'anagrafica_certest_service_id',
ConsegnaRichiesta: 'consegna_richiesta'
};
if (m && m[1]) { if (m && m[1]) {
formData.append(m[1], inp.value); const logicalKey = m[1];
const realKey = fixedAliasMap[logicalKey] || logicalKey;
formData.append(realKey, inp.value);
} }
}); });
formData.append('iddatadb', iddatadb); formData.append('iddatadb', iddatadb);
@@ -1370,11 +1529,10 @@ function fixedDefaultValue(array $f): string
}); });
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500); setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
if (changedFields[rowIndex]) { changedRows.delete(rowIndex);
delete changedFields[rowIndex]; document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`)
document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`) .forEach(cell => cell.classList.remove("cell-changed"));
.forEach(cell => cell.classList.remove("cell-changed"));
}
} else { } else {
errorMessages.push(`Riga ${parseInt(rowIndex) + 1}: ${data.message}`); errorMessages.push(`Riga ${parseInt(rowIndex) + 1}: ${data.message}`);
} }
@@ -1383,8 +1541,9 @@ function fixedDefaultValue(array $f): string
} }
} }
renderChangedList(); renderChangedRows();
hasChanges = Object.keys(changedFields).length > 0; hasChanges = changedRows.size > 0;
if (errorMessages.length === 0) { if (errorMessages.length === 0) {
alert(`Tutte le ${successCount} righe salvate con successo!`); alert(`Tutte le ${successCount} righe salvate con successo!`);
@@ -1511,8 +1670,8 @@ function fixedDefaultValue(array $f): string
// Gestione degli input // Gestione degli input
inputs.forEach(input => { inputs.forEach(input => {
if (input.tagName === 'SELECT' || if (input.tagName === 'SELECT' ||
input.classList.contains('date-picker') || input.classList.contains('date-picker') ||
input.type === 'number' || input.type === 'number' ||
input.type === 'date') { input.type === 'date') {
input.addEventListener('focus', function() { input.addEventListener('focus', function() {
@@ -1532,7 +1691,7 @@ function fixedDefaultValue(array $f): string
expandColumn(cell, true); expandColumn(cell, true);
cell.dataset.convertingToTextarea = 'true'; cell.dataset.convertingToTextarea = 'true';
const textarea = document.createElement('textarea'); const textarea = document.createElement('textarea');
textarea.value = this.value; textarea.value = this.value;
@@ -1546,9 +1705,9 @@ function fixedDefaultValue(array $f): string
textarea.setAttribute('data-current-value', this.getAttribute('data-current-value') || ''); textarea.setAttribute('data-current-value', this.getAttribute('data-current-value') || '');
textarea.setAttribute('data-fixed-key', this.getAttribute('data-fixed-key') || ''); textarea.setAttribute('data-fixed-key', this.getAttribute('data-fixed-key') || '');
textarea.dataset.originalInput = 'true'; textarea.dataset.originalInput = 'true';
this.parentNode.replaceChild(textarea, this); this.parentNode.replaceChild(textarea, this);
setTimeout(() => { setTimeout(() => {
textarea.focus(); textarea.focus();
delete cell.dataset.convertingToTextarea; delete cell.dataset.convertingToTextarea;
@@ -1566,7 +1725,7 @@ function fixedDefaultValue(array $f): string
const element = e.target; const element = e.target;
if (element.tagName === 'TEXTAREA' && element.dataset.originalInput === 'true') { if (element.tagName === 'TEXTAREA' && element.dataset.originalInput === 'true') {
const cell = element.closest('.grid-cell'); const cell = element.closest('.grid-cell');
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'text'; input.type = 'text';
input.value = element.value; input.value = element.value;
@@ -1578,16 +1737,16 @@ function fixedDefaultValue(array $f): string
input.setAttribute('data-selected-value', element.getAttribute('data-selected-value') || ''); input.setAttribute('data-selected-value', element.getAttribute('data-selected-value') || '');
input.setAttribute('data-current-value', element.getAttribute('data-current-value') || ''); input.setAttribute('data-current-value', element.getAttribute('data-current-value') || '');
input.setAttribute('data-fixed-key', element.getAttribute('data-fixed-key') || ''); input.setAttribute('data-fixed-key', element.getAttribute('data-fixed-key') || '');
element.parentNode.replaceChild(input, element); element.parentNode.replaceChild(input, element);
expandColumn(cell, false); expandColumn(cell, false);
input.addEventListener('focus', function() { input.addEventListener('focus', function() {
const cell = this.closest('.grid-cell'); const cell = this.closest('.grid-cell');
expandColumn(cell, true); expandColumn(cell, true);
cell.dataset.convertingToTextarea = 'true'; cell.dataset.convertingToTextarea = 'true';
const textarea = document.createElement('textarea'); const textarea = document.createElement('textarea');
textarea.value = this.value; textarea.value = this.value;
textarea.name = this.name; textarea.name = this.name;
@@ -1600,15 +1759,17 @@ function fixedDefaultValue(array $f): string
textarea.setAttribute('data-current-value', this.getAttribute('data-current-value') || ''); textarea.setAttribute('data-current-value', this.getAttribute('data-current-value') || '');
textarea.setAttribute('data-fixed-key', this.getAttribute('data-fixed-key') || ''); textarea.setAttribute('data-fixed-key', this.getAttribute('data-fixed-key') || '');
textarea.dataset.originalInput = 'true'; textarea.dataset.originalInput = 'true';
this.parentNode.replaceChild(textarea, this); this.parentNode.replaceChild(textarea, this);
setTimeout(() => { setTimeout(() => {
textarea.focus(); textarea.focus();
delete cell.dataset.convertingToTextarea; delete cell.dataset.convertingToTextarea;
}, 0); }, 0);
}); });
const changeEvent = new Event('change', { bubbles: true }); const changeEvent = new Event('change', {
bubbles: true
});
input.dispatchEvent(changeEvent); input.dispatchEvent(changeEvent);
} else if (element.tagName === 'INPUT' && element.type === 'text') { } else if (element.tagName === 'INPUT' && element.type === 'text') {
const cell = element.closest('.grid-cell'); const cell = element.closest('.grid-cell');
@@ -1624,7 +1785,9 @@ function fixedDefaultValue(array $f): string
button.addEventListener('click', async function() { button.addEventListener('click', async function() {
const column = this.getAttribute('data-column'); const column = this.getAttribute('data-column');
const input = this.previousElementSibling; const input = this.previousElementSibling;
const value = input.tagName === 'SELECT' ? input.value : input.value; const value = $(input).hasClass('select2-hidden-accessible') ?
$(input).val() :
(input.tagName === 'SELECT' || input.tagName === 'INPUT' ? input.value : '');
console.log('Propagate clicked for column:', column, 'with value:', value); // Debug console.log('Propagate clicked for column:', column, 'with value:', value); // Debug
@@ -1649,11 +1812,14 @@ function fixedDefaultValue(array $f): string
if (targetInput) { if (targetInput) {
console.log('Setting value on target input:', targetInput, 'with value:', value); // Debug console.log('Setting value on target input:', targetInput, 'with value:', value); // Debug
if (targetInput.tagName === 'SELECT') { if (targetInput.tagName === 'SELECT') {
targetInput.value = value; if ($(targetInput).hasClass('select2-hidden-accessible')) {
const event = new Event('change', { $(targetInput).val(value).trigger('change');
bubbles: true } else {
}); targetInput.value = value;
targetInput.dispatchEvent(event); targetInput.dispatchEvent(new Event('change', {
bubbles: true
}));
}
} else if (targetInput.classList.contains('date-picker')) { } else if (targetInput.classList.contains('date-picker')) {
const flatpickrInstance = targetInput._flatpickr; const flatpickrInstance = targetInput._flatpickr;
if (flatpickrInstance && value) { if (flatpickrInstance && value) {
@@ -1678,6 +1844,16 @@ function fixedDefaultValue(array $f): string
} }
}); });
}); });
requestAnimationFrame(() => {
setTimeout(() => {
autoFitColumnsByHeaderKeepWider({
minPx: 150,
maxPx: 380,
extraPx: 40,
ignoreIndexes: [] // es: ['2'] se vuoi escludere Client
});
}, 50);
});
// Gestione del ridimensionamento delle colonne // Gestione del ridimensionamento delle colonne
const resizers = document.querySelectorAll('.resizer'); const resizers = document.querySelectorAll('.resizer');
@@ -1763,26 +1939,59 @@ function fixedDefaultValue(array $f): string
return; return;
} }
dropdown.innerHTML = '<option value="">Seleziona...</option>'; const items = dropdownData[fieldId];
dropdownData[fieldId].forEach(value => { // ✅ Sort alphabetically by Valore (A→Z)
const option = document.createElement('option'); items.sort((a, b) => String(a.Valore || '').localeCompare(String(b.Valore || ''), 'it', {
option.value = value.IdCustomFieldsValue; sensitivity: 'base'
option.textContent = value.Valore; }));
if (currentValue && currentValue === String(value.IdCustomFieldsValue)) { const valToSelect = currentValue || selectedValue;
option.selected = true;
} else if (!currentValue && selectedValue === String(value.IdCustomFieldsValue)) {
option.selected = true;
}
dropdown.appendChild(option);
});
// Ripristina il valore corrente if (items.length > 12) {
if (currentValue || selectedValue) { // Select2 con ricerca
dropdown.value = currentValue || selectedValue; dropdown.innerHTML = '<option value="">Seleziona...</option>';
const event = new Event('change', { items.forEach(value => {
bubbles: true const option = document.createElement('option');
option.value = value.IdCustomFieldsValue;
option.textContent = value.Valore;
if (valToSelect && valToSelect === String(value.IdCustomFieldsValue)) {
option.selected = true;
}
dropdown.appendChild(option);
}); });
dropdown.dispatchEvent(event); $(dropdown).select2({
placeholder: "Seleziona...",
allowClear: true,
width: '100%'
});
// sposta la select DOPO il container Select2 così previousElementSibling del btn torna corretto
const s2container = $(dropdown).next('.select2-container');
if (s2container.length) {
s2container.after(dropdown);
}
if (valToSelect) {
$(dropdown).val(valToSelect).trigger('change');
}
} else {
// Select nativa
try {
$(dropdown).select2('destroy');
} catch (e) {}
dropdown.innerHTML = '<option value="">Seleziona...</option>';
items.forEach(value => {
const option = document.createElement('option');
option.value = value.IdCustomFieldsValue;
option.textContent = value.Valore;
if (valToSelect && valToSelect === String(value.IdCustomFieldsValue)) {
option.selected = true;
}
dropdown.appendChild(option);
});
if (valToSelect) {
dropdown.value = valToSelect;
dropdown.dispatchEvent(new Event('change', {
bubbles: true
}));
}
} }
}); });
} }
@@ -1820,8 +2029,13 @@ function fixedDefaultValue(array $f): string
clientData.forEach(client => { clientData.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 codice = (client.CodiceNazioneFatturazione || '').trim();
const option = new Option(`${nome.trim()} - ${codice} (ID: ${id})`, id); // CodiceCliente es: "Bl01858_E" -> vogliamo "E"
const codiceCliente = (client.CodiceCliente || '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim(); // parte dopo "_"
const shortCode = suffix || '--';
const option = new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) { if (parseInt(id) === parseInt(<?php echo json_encode($default_idclient ?? 0); ?>)) {
option.selected = true; option.selected = true;
@@ -1852,8 +2066,13 @@ function fixedDefaultValue(array $f): string
clientData.forEach(client => { clientData.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 codice = (client.CodiceNazioneFatturazione || '').trim();
const option = new Option(`${nome.trim()} - ${codice} (ID: ${id})`, id); // CodiceCliente es: "Bl01858_E" -> vogliamo "E"
const codiceCliente = (client.CodiceCliente || '').toString().trim();
const suffix = (codiceCliente.split('_')[1] || '').trim(); // parte dopo "_"
const shortCode = suffix || '--';
const option = new Option(`${nome.trim()} - ${shortCode} (ID: ${id})`, id);
if (String(id) === String(currentValue)) { if (String(id) === String(currentValue)) {
option.selected = true; option.selected = true;
@@ -1952,6 +2171,98 @@ function fixedDefaultValue(array $f): string
}); });
}); });
// Quick add part from "Tested Component" (+ button)
$(document).on('click', '.add-part-btn', async function() {
const rowIndex = $(this).data('row');
const $row = $(this).closest('.grid-row');
const iddatadb = $row.data('id');
// Input inside the same cell
const $cell = $(this).closest('.grid-cell');
const $input = $cell.find('input[name^="rows["][name$="[tested_component]"]');
const raw = ($input.val() || '').trim();
// ✅ split multiplo con "|"
const parts = raw
.split('|')
.map(s => s.trim())
.filter(s => s.length > 0);
// (opzionale) dedup per evitare doppioni tipo "Cap | Cap"
const uniqueParts = [...new Set(parts)];
if (!uniqueParts.length) {
alert('⚠️ Inserisci prima una descrizione nel campo Tested Component.');
$input.focus();
return;
}
try {
let okCount = 0;
const errors = [];
// ✅ esegue una chiamata per ogni parte (compatibile con lattuale add_part_quick.php)
for (const p of uniqueParts) {
const formData = new FormData();
formData.append('iddatadb', iddatadb);
formData.append('part_description', p);
const resp = await fetch('add_part_quick.php', {
method: 'POST',
body: formData
});
let data = {};
try {
data = await resp.json();
} catch (e) {}
if (!resp.ok || !data.success) {
errors.push(`"${p}": ${(data && data.message) ? data.message : ('HTTP ' + resp.status)}`);
} else {
okCount++;
}
}
// feedback UI
$input.addClass('cell-changed');
setTimeout(() => $input.removeClass('cell-changed'), 1200);
$input.trigger('change');
if (errors.length === 0) {
showQuickPartModal(`✅ Parti aggiunte: ${okCount}`);
} else {
// aggiunge comunque se alcune sono ok
showQuickPartModal(`⚠️ Parti aggiunte: ${okCount}\nErrori:\n- ${errors.join('\n- ')}`);
console.error('Add parts errors:', errors);
}
} catch (err) {
alert('❌ Errore aggiunta parti: ' + err.message);
console.error(err);
}
});
function showQuickPartModal(message) {
const modalEl = document.getElementById('quickPartModal');
if (!modalEl) {
alert(message); // fallback se il modal non esiste
return;
}
document.getElementById('quickPartModalMessage').textContent = message;
let modal = bootstrap.Modal.getInstance(modalEl);
if (!modal) modal = new bootstrap.Modal(modalEl, {
backdrop: true,
keyboard: true
});
modal.show();
}
$(document).on('click', '.parts-btn', function() { $(document).on('click', '.parts-btn', function() {
const iddatadb = $(this).data('iddatadb') || null; const iddatadb = $(this).data('iddatadb') || null;
const idquotations = $(this).data('idquotations') || null; const idquotations = $(this).data('idquotations') || null;
@@ -2116,6 +2427,12 @@ function fixedDefaultValue(array $f): string
id: item[config.idKey], id: item[config.idKey],
text: (item.Codice ? item.Codice + ' - ' : '') + (item[config.textKey] || 'Senza nome') text: (item.Codice ? item.Codice + ' - ' : '') + (item[config.textKey] || 'Senza nome')
})); }));
// ✅ Sort alphabetically by text
results.sort((a, b) => String(a.text || '').localeCompare(String(b.text || ''), 'it', {
sensitivity: 'base'
}));
fixedFieldDataCache[cacheKey] = results; fixedFieldDataCache[cacheKey] = results;
return results; return results;
} catch (err) { } catch (err) {
@@ -2175,19 +2492,37 @@ function fixedDefaultValue(array $f): string
id: item[config.idKey], id: item[config.idKey],
text: (item.Codice ? item.Codice + ' - ' : '') + (item[config.textKey] || 'Senza nome') text: (item.Codice ? item.Codice + ' - ' : '') + (item[config.textKey] || 'Senza nome')
})); }));
// ✅ Sort alphabetically by text
results.sort((a, b) => String(a.text || '').localeCompare(String(b.text || ''), 'it', {
sensitivity: 'base'
}));
} else { } else {
results = await loadFixedFieldData(fieldKey); results = await loadFixedFieldData(fieldKey);
} }
$select.select2('destroy').empty().select2({ if (results.length > 12) {
data: [{ // Select2 con ricerca
id: '', $select.select2('destroy').empty().select2({
text: 'Seleziona...' data: [{
}, ...results], id: '',
placeholder: "Seleziona...", text: 'Seleziona...'
allowClear: true, }, ...results],
width: '100%' placeholder: "Seleziona...",
}); allowClear: true,
width: '100%'
});
} else {
// Select nativa senza Select2
try {
$select.select2('destroy');
} catch (e) {}
$select.empty();
$select.append(new Option('Seleziona...', '', true, false));
results.forEach(r => {
$select.append(new Option(r.text, r.id));
});
$select.css('width', '100%');
}
// Imposta valore iniziale // Imposta valore iniziale
if (currentVal) { if (currentVal) {
@@ -2256,7 +2591,7 @@ function fixedDefaultValue(array $f): string
}); });
} }
}); });
// Fix for sticky columns // Fix for sticky columns
const gridContainer = document.querySelector('.grid-container'); const gridContainer = document.querySelector('.grid-container');
if (gridContainer) { if (gridContainer) {
@@ -2266,16 +2601,16 @@ function fixedDefaultValue(array $f): string
row.style.minWidth = 'max-content'; row.style.minWidth = 'max-content';
} }
}); });
const gridTop = document.querySelector('.grid-top'); const gridTop = document.querySelector('.grid-top');
if (gridTop && !gridTop.style.minWidth) { if (gridTop && !gridTop.style.minWidth) {
gridTop.style.minWidth = 'max-content'; gridTop.style.minWidth = 'max-content';
} }
const stickyTopCells = document.querySelectorAll('.grid-top .grid-cell.save-all-cell, .grid-top .grid-cell:nth-child(2)'); const stickyTopCells = document.querySelectorAll('.grid-top .grid-cell.save-all-cell, .grid-top .grid-cell:nth-child(2)');
stickyTopCells.forEach(cell => { stickyTopCells.forEach(cell => {
if (!cell.style.minWidth && !cell.style.flex) { if (!cell.style.minWidth && !cell.style.flex) {
const computedStyle = window.getComputedStyle(cell); const computedStyle = window.getComputedStyle(cell);
if (computedStyle.flex === '0 0 auto' || !computedStyle.flex.includes('0 0')) { if (computedStyle.flex === '0 0 auto' || !computedStyle.flex.includes('0 0')) {
cell.style.minWidth = cell.offsetWidth + 'px'; cell.style.minWidth = cell.offsetWidth + 'px';
@@ -2285,6 +2620,64 @@ function fixedDefaultValue(array $f): string
} }
}); });
</script> </script>
<script>
function autoFitColumnsByHeaderKeepWider({
minPx = 150,
maxPx = 380, // limite solo per l'auto-fit (NON riduce se già più largo)
extraPx = 40,
ignoreIndexes = []
} = {}) {
// misura testo con stesso font dell'header
const measurer = document.createElement('span');
measurer.style.position = 'absolute';
measurer.style.visibility = 'hidden';
measurer.style.whiteSpace = 'nowrap';
measurer.style.left = '-99999px';
measurer.style.top = '-99999px';
document.body.appendChild(measurer);
const headers = document.querySelectorAll('.grid-row .grid-header[data-index]');
headers.forEach(header => {
const idx = header.getAttribute('data-index');
if (!idx || ignoreIndexes.includes(String(idx))) return;
// testo header senza il resizer
const clone = header.cloneNode(true);
clone.querySelectorAll('.resizer').forEach(r => r.remove());
const label = (clone.textContent || '').replace(/\s+/g, ' ').trim();
// misura
const headerStyle = window.getComputedStyle(header);
measurer.style.font = headerStyle.font; // importante: usa stesso font completo
measurer.textContent = label;
let desired = Math.ceil(measurer.offsetWidth + extraPx);
desired = Math.max(minPx, desired);
desired = Math.min(maxPx, desired); // clamp SOLO della misura calcolata
// larghezza corrente (flex-basis), fallback a offsetWidth
const cs = window.getComputedStyle(header);
let current = parseFloat(cs.flexBasis);
if (Number.isNaN(current) || !current) current = header.offsetWidth;
// ✅ non restringere mai
const finalWidth = Math.max(current, desired);
// applica a header + celle + top
const targets = document.querySelectorAll(
`.grid-header[data-index="${idx}"], .grid-cell[data-index="${idx}"], .grid-top .grid-cell[data-index="${idx}"]`
);
targets.forEach(el => {
el.style.flex = `0 0 ${finalWidth}px`;
});
});
measurer.remove();
}
</script>
<!-- Modale di conferma per l'esportazione --> <!-- Modale di conferma per l'esportazione -->
<div class="modal fade" id="exportConfirmModal" tabindex="-1" aria-labelledby="exportConfirmModalLabel" aria-hidden="true"> <div class="modal fade" id="exportConfirmModal" tabindex="-1" aria-labelledby="exportConfirmModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
+4 -3
View File
@@ -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;
+56 -11
View File
@@ -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>
@@ -305,13 +315,12 @@ error_log("Loaded template: " . print_r($template, true));
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...">
</div>
<div class="table-container"> <div class="table-container">
<table class="table table-striped table-bordered"> <table class="table table-striped table-bordered">
<thead> <thead>
@@ -319,6 +328,17 @@ error_log("Loaded template: " . print_r($template, true));
<th><input type="checkbox" id="selectAll"> Seleziona</th> <th><input type="checkbox" id="selectAll"> Seleziona</th>
${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')} ${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')}
</tr> </tr>
<tr class="column-filters">
<th></th>
${data.columns.map((col, i) => `
<th>
<input type="text"
class="form-control form-control-sm column-filter"
data-col-index="${i}"
placeholder="Filter...">
</th>
`).join('')}
</tr>
</thead> </thead>
<tbody> <tbody>
${data.excel_data.map((row, index) => ` ${data.excel_data.map((row, index) => `
@@ -393,14 +413,39 @@ 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(' '); // Le celle di data partono da index 1 (perché index 0 è checkbox)
row.style.display = text.includes(searchTerm) ? '' : 'none'; let visible = true;
for (const [colIndexStr, filterValue] of Object.entries(activeFilters)) {
const colIndex = parseInt(colIndexStr, 10); // 0..N-1 sulle colonne dati
const cell = row.cells[colIndex + 1]; // +1 per saltare la colonna checkbox
const cellText = (cell?.textContent || '').toLowerCase();
const searchText = (filterValue || '').toLowerCase().trim();
if (searchText && !cellText.includes(searchText)) {
visible = false;
break;
}
}
row.style.display = visible ? '' : 'none';
});
}
filterInputs.forEach(input => {
input.addEventListener('input', function() {
const colIndex = this.dataset.colIndex; // string
activeFilters[colIndex] = this.value;
applyColumnFilters();
}); });
}); });
+2 -9
View File
@@ -35,8 +35,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 +47,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");
?>
+179 -10
View File
@@ -21,7 +21,7 @@ $schemajson = $template['schemajson'] ? json_decode($template['schemajson'], tru
$isSchemajsonEmpty = empty(trim($template['schemajson'])); $isSchemajsonEmpty = empty(trim($template['schemajson']));
// Recupera i campi dalla tabella template_mapping // Recupera i campi dalla tabella template_mapping
$stmt = $pdo->prepare("SELECT id, field_id, excel_column, is_manual, manual_default, data_type, is_required, default_value, has_list, length, decimals, min_value, max_value, default_curr_date, tablename, field_label, main_field, is_visible_import FROM template_mapping WHERE template_id = ?"); $stmt = $pdo->prepare("SELECT id, field_id, excel_column, is_manual, manual_default, auto_value, data_type, is_required, default_value, has_list, length, decimals, min_value, max_value, default_curr_date, tablename, field_label, main_field, is_visible_import, is_visible_parts FROM template_mapping WHERE template_id = ?");
$stmt->execute([$id]); $stmt->execute([$id]);
$mappings = $stmt->fetchAll(PDO::FETCH_ASSOC); $mappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -108,6 +108,14 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
.select2-container { .select2-container {
width: 100% !important; width: 100% !important;
} }
/* Make Title column narrower + ellipsis */
#schemaFieldsTable td.title-col {
max-width: 320px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style> </style>
</head> </head>
@@ -157,9 +165,10 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
<table id="schemaFieldsTable" class="table table-striped"> <table id="schemaFieldsTable" class="table table-striped">
<thead> <thead>
<tr> <tr>
<th style="width:100px; text-align:center;">Main</th> <th style="width:90px; text-align:center;">Main</th>
<th style="width:120px; text-align:center;">Visible on Import</th> <th style="width:110px; text-align:center;">Import</th>
<th>Title</th> <th style="width:110px; text-align:center;">Parts</th>
<th style="width:320px;">Title</th>
<th style="width:140px;">Type</th> <th style="width:140px;">Type</th>
<th>Mapping</th> <th>Mapping</th>
<th>Default Value</th> <th>Default Value</th>
@@ -169,6 +178,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
<tbody id="schemaFieldsBody"> <tbody id="schemaFieldsBody">
<?php foreach ($mappings as $mapping): ?> <?php foreach ($mappings as $mapping): ?>
<tr> <tr>
@@ -185,22 +195,34 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
data-mapping-id="<?php echo (int)$mapping['id']; ?>" data-mapping-id="<?php echo (int)$mapping['id']; ?>"
<?php echo ((int)($mapping['is_visible_import'] ?? 1) === 1) ? 'checked' : ''; ?>> <?php echo ((int)($mapping['is_visible_import'] ?? 1) === 1) ? 'checked' : ''; ?>>
</td> </td>
<td class="text-center">
<input type="checkbox"
class="visible-parts-checkbox"
data-mapping-id="<?php echo (int)$mapping['id']; ?>"
<?php echo ((int)($mapping['is_visible_parts'] ?? 0) === 1) ? 'checked' : ''; ?>>
</td>
<td>
<td class="title-col">
<?php echo htmlspecialchars($mapping['field_label'] ?? 'N/A'); ?> <?php echo htmlspecialchars($mapping['field_label'] ?? 'N/A'); ?>
<?php if ((int)$mapping['is_required'] === 1): ?> <?php if ((int)$mapping['is_required'] === 1): ?>
<span class="badge bg-danger ms-2">Required</span> <span class="badge bg-danger ms-2">Required</span>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td><?php echo htmlspecialchars($mapping['data_type'] ?? 'N/A'); ?></td> <td><?php echo htmlspecialchars($mapping['data_type'] ?? 'N/A'); ?></td>
<td> <td>
<?php <?php
$isSceltaMultipla = ($mapping['data_type'] === 'SceltaMultipla'); $isSceltaMultipla = ($mapping['data_type'] === 'SceltaMultipla');
$autoValue = $mapping['auto_value'] ?? 'none';
$hasAuto = ($autoValue && $autoValue !== 'none');
$mappingValue = $isSceltaMultipla $mappingValue = $isSceltaMultipla
? 'manual' ? 'manual'
: ($mapping['excel_column'] ? 'xls' : ((int)$mapping['is_manual'] === 1 ? 'manual' : '')); : ($hasAuto ? 'auto' : ($mapping['excel_column'] ? 'xls' : ((int)$mapping['is_manual'] === 1 ? 'manual' : '')));
?> ?>
<select class="form-select mapping-select" <select class="form-select mapping-select"
@@ -211,6 +233,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
<?php if (!$isSceltaMultipla): ?> <?php if (!$isSceltaMultipla): ?>
<option value="">Select Option</option> <option value="">Select Option</option>
<option value="xls" <?php echo ($mappingValue === 'xls') ? 'selected' : ''; ?>>Map to XLS Column</option> <option value="xls" <?php echo ($mappingValue === 'xls') ? 'selected' : ''; ?>>Map to XLS Column</option>
<option value="auto" <?php echo ($mappingValue === 'auto') ? 'selected' : ''; ?>>Auto value</option>
<?php endif; ?> <?php endif; ?>
<option value="manual" <?php echo ($mappingValue === 'manual') ? 'selected' : ''; ?>>Manual Entry</option> <option value="manual" <?php echo ($mappingValue === 'manual') ? 'selected' : ''; ?>>Manual Entry</option>
@@ -222,6 +245,16 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
<?php echo $mapping['excel_column'] ? 'data-current-xls="' . htmlspecialchars($mapping['excel_column']) . '"' : ''; ?>> <?php echo $mapping['excel_column'] ? 'data-current-xls="' . htmlspecialchars($mapping['excel_column']) . '"' : ''; ?>>
</select> </select>
<select class="form-select auto-value-select"
style="display:<?php echo ($mappingValue === 'auto') ? 'block' : 'none'; ?>; margin-top:6px;"
data-id="<?php echo (int)$mapping['id']; ?>">
<option value="none">Select auto value</option>
<option value="import_date" <?php echo ($autoValue === 'import_date') ? 'selected' : ''; ?>>Current date (import)</option>
<option value="import_time" <?php echo ($autoValue === 'import_time') ? 'selected' : ''; ?>>Current time (import)</option>
<option value="export_date" <?php echo ($autoValue === 'export_date') ? 'selected' : ''; ?>>Current date (export)</option>
<option value="export_time" <?php echo ($autoValue === 'export_time') ? 'selected' : ''; ?>>Current time (export)</option>
</select>
<?php if (!empty($mapping['excel_column'])): ?> <?php if (!empty($mapping['excel_column'])): ?>
<span class="mapped-column" style="margin-left:5px;"> <span class="mapped-column" style="margin-left:5px;">
(<?php echo htmlspecialchars($mapping['excel_column']); ?>) (<?php echo htmlspecialchars($mapping['excel_column']); ?>)
@@ -248,7 +281,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
class="form-control manual-default" class="form-control manual-default"
placeholder="Default value" placeholder="Default value"
value="<?php echo htmlspecialchars($mapping['manual_default'] ?? ''); ?>" value="<?php echo htmlspecialchars($mapping['manual_default'] ?? ''); ?>"
style="display:<?php echo ((int)$mapping['is_manual'] === 1) ? 'block' : 'none'; ?>" style="display:<?php echo ($mappingValue === 'manual') ? 'block' : 'none'; ?>"
data-field-id="<?php echo (int)$mapping['field_id']; ?>"> data-field-id="<?php echo (int)$mapping['field_id']; ?>">
<?php endif; ?> <?php endif; ?>
</td> </td>
@@ -665,6 +698,61 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
loadDropdownsWithOverlay(); loadDropdownsWithOverlay();
// =======================
// SAVE: SceltaMultipla dropdown (Select2-safe)
// =======================
// 1) listener nativo a livello document (più robusto del delegation su tbody)
document.addEventListener('change', function(event) {
const el = event.target;
if (!(el && el.matches && el.matches('select.manual-default.dropdown-select'))) return;
const tr = el.closest('tr');
const mappingId =
el.getAttribute('data-id') ||
tr?.querySelector('.mapping-select')?.getAttribute('data-id');
const xlsSelect = tr?.querySelector('.xls-columns');
console.log('[SceltaMultipla change] saving', {
mappingId,
value: el.value
});
if (!mappingId) {
console.error('❌ Missing mappingId for SceltaMultipla dropdown');
return;
}
saveMapping(mappingId, 'manual', el.value, xlsSelect ? xlsSelect.value : null);
});
// 2) eventi Select2 (quando Select2 “mangia” il change)
if (window.jQuery) {
$(document).on('select2:select select2:clear', 'select.manual-default.dropdown-select', function() {
const el = this;
const tr = el.closest('tr');
const mappingId =
el.getAttribute('data-id') ||
tr?.querySelector('.mapping-select')?.getAttribute('data-id');
const xlsSelect = tr?.querySelector('.xls-columns');
console.log('[SceltaMultipla select2] saving', {
mappingId,
value: el.value
});
if (!mappingId) {
console.error('❌ Missing mappingId for SceltaMultipla dropdown (select2)');
return;
}
saveMapping(mappingId, 'manual', el.value, xlsSelect ? xlsSelect.value : null);
});
}
async function loadClientAndSchemaNames() { async function loadClientAndSchemaNames() {
if (<?php echo json_encode($template['idclient'] ?? 0); ?> > 0) { if (<?php echo json_encode($template['idclient'] ?? 0); ?> > 0) {
let response = await fetch(`get_clienti.php?id=<?php echo $template['idclient']; ?>`); let response = await fetch(`get_clienti.php?id=<?php echo $template['idclient']; ?>`);
@@ -729,27 +817,57 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
let mappingId = event.target.getAttribute('data-id'); let mappingId = event.target.getAttribute('data-id');
let xlsSelect = tr.querySelector('.xls-columns'); let xlsSelect = tr.querySelector('.xls-columns');
let manualInput = tr.querySelector('.manual-default'); let manualInput = tr.querySelector('.manual-default');
let autoSelect = tr.querySelector('.auto-value-select');
let mappedColumn = tr.querySelector('.mapped-column'); let mappedColumn = tr.querySelector('.mapped-column');
let removeBtn = tr.querySelector('.remove-xls'); let removeBtn = tr.querySelector('.remove-xls');
if (event.target.value === 'xls') { if (event.target.value === 'xls') {
xlsSelect.style.display = 'block'; xlsSelect.style.display = 'block';
if (autoSelect) autoSelect.style.display = 'none';
manualInput.style.display = 'none'; manualInput.style.display = 'none';
manualInput.value = ''; manualInput.value = '';
if (mappedColumn) mappedColumn.style.display = 'none'; if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = xlsSelect.value ? 'inline-block' : 'none'; if (removeBtn) removeBtn.style.display = xlsSelect.value ? 'inline-block' : 'none';
} else if (event.target.value === 'manual') { } else if (event.target.value === 'manual') {
xlsSelect.style.display = 'none'; xlsSelect.style.display = 'none';
if (autoSelect) autoSelect.style.display = 'none';
manualInput.style.display = 'block'; manualInput.style.display = 'block';
if (mappedColumn) mappedColumn.style.display = 'none'; if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = 'none'; if (removeBtn) removeBtn.style.display = 'none';
} else {
} else if (event.target.value === 'auto') {
xlsSelect.style.display = 'none'; xlsSelect.style.display = 'none';
xlsSelect.value = ''; // libera UI
manualInput.style.display = 'none'; manualInput.style.display = 'none';
manualInput.value = ''; manualInput.value = '';
if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = 'none';
if (autoSelect) autoSelect.style.display = 'block';
} else {
xlsSelect.style.display = 'none';
if (autoSelect) autoSelect.style.display = 'none';
manualInput.style.display = 'none';
manualInput.value = '';
if (mappedColumn) mappedColumn.style.display = 'none'; if (mappedColumn) mappedColumn.style.display = 'none';
if (removeBtn) removeBtn.style.display = 'none'; if (removeBtn) removeBtn.style.display = 'none';
} }
saveMapping(mappingId, event.target.value, manualInput.value, xlsSelect.value); saveMapping(
mappingId,
event.target.value,
manualInput.value,
xlsSelect.value,
autoSelect ? autoSelect.value : null
);
updateXlsDropdowns(); updateXlsDropdowns();
} else if (event.target.classList.contains('main-field-checkbox')) { } else if (event.target.classList.contains('main-field-checkbox')) {
const checkbox = event.target; const checkbox = event.target;
@@ -822,19 +940,65 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
console.error("❌ Fetch error:", error); console.error("❌ Fetch error:", error);
checkbox.checked = !checkbox.checked; checkbox.checked = !checkbox.checked;
}); });
} else if (event.target.classList.contains('visible-parts-checkbox')) {
const checkbox = event.target;
const mappingId = checkbox.dataset.mappingId;
const value = checkbox.checked ? 1 : 0;
fetch('update_visible_parts.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
template_id: <?php echo $id; ?>,
mapping_id: mappingId,
value: value
})
})
.then(response => response.json())
.then(data => {
if (!data.success) {
console.error("❌ Error updating is_visible_parts:", data.message);
checkbox.checked = !checkbox.checked;
}
})
.catch(error => {
console.error("❌ Fetch error:", error);
checkbox.checked = !checkbox.checked;
});
} }
}); });
// Salva lo stato originale dei checkbox al caricamento // Salva lo stato originale dei checkbox al caricamento
document.querySelectorAll('.main-field-checkbox').forEach(cb => { document.querySelectorAll('.main-field-checkbox').forEach(cb => {
cb.dataset.originalChecked = cb.checked; cb.dataset.originalChecked = cb.checked;
}); });
// AUTO VALUE select change -> save auto_value
document.getElementById('schemaFieldsBody').addEventListener('change', function(event) {
if (!event.target.classList.contains('auto-value-select')) return;
const tr = event.target.closest('tr');
const mappingId = event.target.getAttribute('data-id');
const xlsSelect = tr.querySelector('.xls-columns');
const manualInput = tr.querySelector('.manual-default');
saveMapping(
mappingId,
'auto',
manualInput ? manualInput.value : '',
xlsSelect ? xlsSelect.value : null,
event.target.value
);
});
document.getElementById('schemaFieldsBody').addEventListener('change', function(event) { document.getElementById('schemaFieldsBody').addEventListener('change', function(event) {
if (event.target.classList.contains('xls-columns')) { if (event.target.classList.contains('xls-columns')) {
let tr = event.target.closest('tr'); let tr = event.target.closest('tr');
let mappingId = event.target.getAttribute('data-id'); let mappingId = event.target.getAttribute('data-id');
let manualInput = tr.querySelector('.manual-default'); let manualInput = tr.querySelector('.manual-default');
let autoSelect = tr.querySelector('.auto-value-select');
let mappedColumn = tr.querySelector('.mapped-column'); let mappedColumn = tr.querySelector('.mapped-column');
let removeBtn = tr.querySelector('.remove-xls'); let removeBtn = tr.querySelector('.remove-xls');
@@ -875,6 +1039,10 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
mappedColumn.style.display = event.target.value ? 'inline' : 'none'; mappedColumn.style.display = event.target.value ? 'inline' : 'none';
} }
if (removeBtn) removeBtn.style.display = event.target.value ? 'inline-block' : 'none'; if (removeBtn) removeBtn.style.display = event.target.value ? 'inline-block' : 'none';
const mappingSelect = tr.querySelector('.mapping-select');
if (mappingSelect && mappingSelect.value !== 'xls') {
return; // non salvare XLS se non siamo in modalità XLS
}
saveMapping(mappingId, 'xls', manualInput.value, event.target.value); saveMapping(mappingId, 'xls', manualInput.value, event.target.value);
updateXlsDropdowns(); updateXlsDropdowns();
} }
@@ -926,7 +1094,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
} }
}); });
function saveMapping(mappingId, mappingType, defaultValue, excelColumn) { function saveMapping(mappingId, mappingType, defaultValue, excelColumn, autoValue) {
console.log("Saving mapping:", { console.log("Saving mapping:", {
id: mappingId, id: mappingId,
mapping_type: mappingType, mapping_type: mappingType,
@@ -943,6 +1111,7 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
mapping_type: mappingType, mapping_type: mappingType,
excel_column: mappingType === 'xls' ? excelColumn : null, excel_column: mappingType === 'xls' ? excelColumn : null,
manual_default: mappingType === 'manual' ? defaultValue : null, manual_default: mappingType === 'manual' ? defaultValue : null,
auto_value: mappingType === 'auto' ? (autoValue || 'none') : 'none',
tablename: "<?php echo $template['target_table']; ?>" tablename: "<?php echo $template['target_table']; ?>"
}) })
}).then(response => response.json()) }).then(response => response.json())
+68 -22
View File
@@ -12,11 +12,23 @@ 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();
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection(); $pdo = $db->getConnection();
// ---------------- FIXED FIELDS (template_fixed_mapping) ---------------- // ---------------- 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',
'MoltiplicatorePrezzo' => 'moltiplicatore_prezzo_id',
'AnagraficaCertestObject' => 'anagrafica_certest_object_id',
'AnagraficaCertestService' => 'anagrafica_certest_service_id',
'ClienteFornitore' => 'cliente_fornitore_id',
'ConsegnaRichiesta' => 'consegna_richiesta',
];
// 1) Recupera templateid dalla riga datadb (serve per sapere quali fixed_field_key sono permessi) // 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 = $pdo->prepare("SELECT templateid FROM datadb WHERE iddatadb = ?");
$stmtTpl->execute([$iddatadb]); $stmtTpl->execute([$iddatadb]);
@@ -29,30 +41,44 @@ try {
// 2) Recupera elenco fixed fields visibili per quel template // 2) Recupera elenco fixed fields visibili per quel template
$fxStmt = $pdo->prepare(" $fxStmt = $pdo->prepare("
SELECT fixed_field_key, data_type, is_required, default_value SELECT fixed_field_key, data_type, is_required, default_value
FROM template_fixed_mapping FROM template_fixed_mapping
WHERE template_id = ? AND is_visible_import = 1 WHERE template_id = ? AND is_visible_import = 1
"); ");
$fxStmt->execute([$templateId]); $fxStmt->execute([$templateId]);
$fixedList = $fxStmt->fetchAll(PDO::FETCH_ASSOC); $fixedList = $fxStmt->fetchAll(PDO::FETCH_ASSOC);
// 3) Crea whitelist: key => metadata // 3) Crea whitelist LOGICA: fixed_field_key => metadata
$fixedWhitelist = []; $fixedWhitelist = [];
foreach ($fixedList as $fx) { foreach ($fixedList as $fx) {
$k = (string)$fx['fixed_field_key']; $k = (string)$fx['fixed_field_key'];
// sicurezza: nome colonna ammesso solo se "safe" (no spazi, no caratteri strani) // sicurezza: key ammessa solo se "safe"
if (!preg_match('/^[a-zA-Z0-9_]+$/', $k)) { if (!preg_match('/^[a-zA-Z0-9_]+$/', $k)) {
continue; continue;
} }
$fixedWhitelist[$k] = [ $fixedWhitelist[$k] = [
'data_type' => (string)$fx['data_type'], // INT | DATE 'data_type' => (string)$fx['data_type'], // INT | DATE
'is_required' => (int)$fx['is_required'], 'is_required' => (int)$fx['is_required'],
'default_value' => $fx['default_value'] ?? null '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 = [];
@@ -94,30 +120,50 @@ 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 datadb: idclient + FIXED FIELDS (whitelisted) // ---------------- UPDATE datadb: idclient + FIXED FIELDS ----------------
$setParts = []; $setParts = [];
$params = []; $params = [];
// 5a) idclient (se presente) // 5a) idclient (se presente)
if (isset($idclient)) { if (isset($idclient)) {
$setParts[] = "idclient = ?"; $setParts[] = "idclient = ?";
$params[] = $idclient; $params[] = $idclient;
} }
// 5b) fixed fields dal POST (solo quelli presenti nella whitelist del template) // 5b) fixed fields dal POST
foreach ($fixedWhitelist as $col => $meta) { // QUI è il punto chiave: accettiamo SOLO colonne reali (realWhitelist),
if (!array_key_exists($col, $_POST)) { // ma se dal JS arrivassero ancora key logiche, funzionerebbe uguale
continue; // non inviato dal form // 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;
}
}
} }
$val = $_POST[$col]; if ($postKeyToRead === null) {
continue; // non inviato
}
$val = $_POST[$postKeyToRead];
// Normalizzazione per tipo // Normalizzazione per tipo
if ($meta['data_type'] === 'DATE') { if ($meta['data_type'] === 'DATE') {
@@ -128,13 +174,14 @@ try {
$val = ($val === '') ? null : (int)$val; $val = ($val === '') ? null : (int)$val;
} }
$setParts[] = "`$col` = ?"; $setParts[] = "`$realCol` = ?";
$params[] = $val; $params[] = $val;
} }
// esegui update solo se c'è qualcosa da aggiornare // esegui update solo se c'è qualcosa da aggiornare
if (!empty($setParts)) { if (!empty($setParts)) {
$params[] = $iddatadb; $params[] = $iddatadb;
$sqlUpd = "UPDATE datadb SET " . implode(", ", $setParts) . " WHERE iddatadb = ?"; $sqlUpd = "UPDATE datadb SET " . implode(", ", $setParts) . " WHERE iddatadb = ?";
$updStmt = $pdo->prepare($sqlUpd); $updStmt = $pdo->prepare($sqlUpd);
$updStmt->execute($params); $updStmt->execute($params);
@@ -151,7 +198,6 @@ try {
$response['message'] = "No changes found"; $response['message'] = "No changes found";
} }
$response['success'] = true; $response['success'] = true;
$response['changed'] = $changed; // Debug / optional $response['changed'] = $changed; // Debug / optional
+67 -4
View File
@@ -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()]);
} }
File diff suppressed because one or more lines are too long
+14 -2
View File
@@ -1,5 +1,5 @@
{ {
"@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,
@@ -460,7 +460,7 @@
{ {
"IdSchemaCustomFields": 129, "IdSchemaCustomFields": 129,
"ConteggioClienti": 0, "ConteggioClienti": 0,
"Nome": "Carhartt", "Nome": "Z_Carhartt",
"Descrizione": "SCHEMA DA UTILIZZARE SOLO PER RICHIESTE UFFICIALI CARHARTT\r\n\r\n\r\n" "Descrizione": "SCHEMA DA UTILIZZARE SOLO PER RICHIESTE UFFICIALI CARHARTT\r\n\r\n\r\n"
}, },
{ {
@@ -864,6 +864,18 @@
"ConteggioClienti": 0, "ConteggioClienti": 0,
"Nome": "HERMES PAP FEMME", "Nome": "HERMES PAP FEMME",
"Descrizione": "Schema per tutti i campioni di HERMES PAP FEMME \r\n15\/01\/2025\r\n\r\n\r\n" "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"
} }
] ]
} }
+31
View File
@@ -0,0 +1,31 @@
<?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();
$stmt = $pdo->prepare("UPDATE template_mapping SET is_visible_parts = ? WHERE id = ? AND template_id = ?");
$result = $stmt->execute([$value, $mapping_id, $template_id]);
if ($result) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to update is_visible_parts']);
}