Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d692614f70 | |||
| 1303cff9fd | |||
| 6b2bd0964b | |||
| 0d2cf13524 | |||
| f6ef9c39d2 | |||
| 7e4ed56f28 | |||
| 06dd7883c2 | |||
| 4d0644f46c | |||
| 712042b8d8 | |||
| efee12740d | |||
| 14395810d0 | |||
| 03002a8938 | |||
| 21fcee8ff5 | |||
| 1361340928 | |||
| 1bda30e957 | |||
| a87423d879 | |||
| 24cda34681 | |||
| 22e4e652b5 | |||
| 2c514a8ab6 | |||
| b1ea728c15 | |||
| 9d5c20113f | |||
| 47762a8557 | |||
| 939a4fe03e | |||
| 493de65892 | |||
| d8eca66747 | |||
| 23ae8e1b1d | |||
| 7ad20993d9 |
@@ -42,4 +42,6 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
|||||||
# Credenziali API VisualLims
|
# Credenziali API VisualLims
|
||||||
API_BASE_URL=https://93.43.5.102/limsapi
|
API_BASE_URL=https://93.43.5.102/limsapi
|
||||||
API_USERNAME=WebApiUser
|
API_USERNAME=WebApiUser
|
||||||
API_PASSWORD=webapiuser01
|
API_PASSWORD=webapiuser01
|
||||||
|
|
||||||
|
BASE_URL=http://localhost:8000/userarea/
|
||||||
@@ -43,3 +43,12 @@ public/userarea/class/curl_request_debug.log
|
|||||||
public/userarea/last_url.txt
|
public/userarea/last_url.txt
|
||||||
public/userarea/class/curl_auth_debug.log
|
public/userarea/class/curl_auth_debug.log
|
||||||
public/userarea/class/curl_request_debug.log
|
public/userarea/class/curl_request_debug.log
|
||||||
|
|
||||||
|
# Ignora tutti i log
|
||||||
|
*.log
|
||||||
|
|
||||||
|
|
||||||
|
# Ignora cartella photostrf in public/userarea
|
||||||
|
/public/userarea/photostrf/
|
||||||
|
public/userarea/customfield_values_response.json
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Userarea;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class UploadPhotosMobileController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$iddatadb = $request->query('iddatadb');
|
||||||
|
|
||||||
|
if (empty($iddatadb)) {
|
||||||
|
return response('ID riga non fornito', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the upload form
|
||||||
|
return view('userarea.upload_photos_mobile', [
|
||||||
|
'iddatadb' => $iddatadb
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function upload(Request $request)
|
||||||
|
{
|
||||||
|
// Validation
|
||||||
|
$request->validate([
|
||||||
|
'photo' => 'required|file|mimes:jpeg,png,gif,heic,heif|max:5120', // 5MB
|
||||||
|
'iddatadb' => 'required|integer'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$iddatadb = $request->input('iddatadb');
|
||||||
|
$photo = $request->file('photo');
|
||||||
|
$iduserlogin = auth()->id(); // assuming Laravel authentication
|
||||||
|
|
||||||
|
// Check if user exists
|
||||||
|
$userExists = DB::table('auth_users')->where('id', $iduserlogin)->exists();
|
||||||
|
if (!$userExists) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Utente non valido']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload folder
|
||||||
|
$uploadDir = public_path('photostrf');
|
||||||
|
if (!is_dir($uploadDir)) {
|
||||||
|
mkdir($uploadDir, 0755, true);
|
||||||
|
}
|
||||||
|
if (!is_writable($uploadDir)) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'La cartella photostrf non è scrivibile']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New filename
|
||||||
|
$timestamp = now()->format('YmdHis');
|
||||||
|
$originalName = pathinfo($photo->getClientOriginalName(), PATHINFO_FILENAME);
|
||||||
|
$extension = strtolower($photo->getClientOriginalExtension());
|
||||||
|
|
||||||
|
$newFileName = "{$iddatadb}-{$timestamp}-{$originalName}.{$extension}";
|
||||||
|
$destination = $uploadDir . '/' . $newFileName;
|
||||||
|
|
||||||
|
// Move uploaded file
|
||||||
|
$photo->move($uploadDir, $newFileName);
|
||||||
|
|
||||||
|
// Save DB record
|
||||||
|
DB::table('datadb_photos')->insert([
|
||||||
|
'iddatadb' => $iddatadb,
|
||||||
|
'file_path' => $newFileName,
|
||||||
|
'file_name' => $newFileName,
|
||||||
|
'uploaded_by' => $iduserlogin
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json(['success' => true, 'message' => 'Foto caricata con successo']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 510 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 443 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 454 B |
|
After Width: | Height: | Size: 456 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 457 B |
|
After Width: | Height: | Size: 454 B |
|
After Width: | Height: | Size: 455 B |
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 3) . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Dotenv\Dotenv;
|
||||||
|
|
||||||
|
class VisualLimsApiClientXml
|
||||||
|
{
|
||||||
|
private static $instance = null;
|
||||||
|
private $baseUrl;
|
||||||
|
private $username;
|
||||||
|
private $password;
|
||||||
|
private $token = null;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3));
|
||||||
|
$dotenv->load();
|
||||||
|
|
||||||
|
$this->baseUrl = $_ENV['API_BASE_URL'];
|
||||||
|
$this->username = $_ENV['API_USERNAME'];
|
||||||
|
$this->password = $_ENV['API_PASSWORD'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getInstance()
|
||||||
|
{
|
||||||
|
if (self::$instance === null) {
|
||||||
|
self::$instance = new VisualLimsApiClientXml();
|
||||||
|
}
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function authenticate()
|
||||||
|
{
|
||||||
|
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||||
|
'Username' => $this->username,
|
||||||
|
'Password' => $this->password
|
||||||
|
]));
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Accept: application/json'
|
||||||
|
]);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
$log = fopen(__DIR__ . '/curl_auth_debug_xml.log', 'w') ?: fopen('php://stderr', 'w');
|
||||||
|
curl_setopt($ch, CURLOPT_STDERR, $log);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
fclose($log);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false || $http_code != 200) {
|
||||||
|
throw new Exception("Autenticazione fallita: HTTP {$http_code}, Errore cURL: {$curl_error}, Risposta: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
$token_data = json_decode($response, true);
|
||||||
|
$this->token = null;
|
||||||
|
|
||||||
|
if (is_array($token_data) && isset($token_data['token'])) {
|
||||||
|
$this->token = $token_data['token'];
|
||||||
|
} elseif (is_string($token_data) && !empty($token_data)) {
|
||||||
|
$this->token = trim($token_data, '"');
|
||||||
|
} elseif (is_string($response) && !empty($response)) {
|
||||||
|
$this->token = trim($response, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->token)) {
|
||||||
|
throw new Exception("Token non ricevuto: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getToken()
|
||||||
|
{
|
||||||
|
if ($this->token === null) {
|
||||||
|
$this->authenticate();
|
||||||
|
}
|
||||||
|
return $this->token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($endpoint, $options = [])
|
||||||
|
{
|
||||||
|
$token = $this->getToken();
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$url = "{$this->baseUrl}/api/odata/{$endpoint}" . ($query ? '?' . $query : '');
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
"Authorization: Bearer {$token}",
|
||||||
|
"Accept: application/xml"
|
||||||
|
]);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
$log = fopen(__DIR__ . '/curl_request_debug_xml.log', 'w') ?: fopen('php://stderr', 'w');
|
||||||
|
curl_setopt($ch, CURLOPT_STDERR, $log);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
fclose($log);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false) {
|
||||||
|
throw new Exception("Errore nella richiesta: {$curl_error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($http_code !== 200) {
|
||||||
|
throw new Exception("Errore nel recupero dati: HTTP {$http_code}, Risposta: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica che la risposta sia XML
|
||||||
|
if (strpos($response, '<?xml') !== 0) {
|
||||||
|
throw new Exception("Risposta non valida: atteso formato XML, ricevuto: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 3) . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Dotenv\Dotenv;
|
||||||
|
|
||||||
|
class VisualLimsApiClientXml
|
||||||
|
{
|
||||||
|
private static $instance = null;
|
||||||
|
private $baseUrl;
|
||||||
|
private $username;
|
||||||
|
private $password;
|
||||||
|
private $token = null;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3));
|
||||||
|
$dotenv->load();
|
||||||
|
|
||||||
|
$this->baseUrl = $_ENV['API_BASE_URL'];
|
||||||
|
$this->username = $_ENV['API_USERNAME'];
|
||||||
|
$this->password = $_ENV['API_PASSWORD'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getInstance()
|
||||||
|
{
|
||||||
|
if (self::$instance === null) {
|
||||||
|
self::$instance = new VisualLimsApiClientXml();
|
||||||
|
}
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function authenticate()
|
||||||
|
{
|
||||||
|
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
|
||||||
|
'Username' => $this->username,
|
||||||
|
'Password' => $this->password
|
||||||
|
]));
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Accept: application/json'
|
||||||
|
]);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
$log = fopen(__DIR__ . '/curl_auth_debug_xml.log', 'w') ?: fopen('php://stderr', 'w');
|
||||||
|
curl_setopt($ch, CURLOPT_STDERR, $log);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
fclose($log);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false || $http_code != 200) {
|
||||||
|
throw new Exception("Autenticazione fallita: HTTP {$http_code}, Errore cURL: {$curl_error}, Risposta: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
$token_data = json_decode($response, true);
|
||||||
|
$this->token = null;
|
||||||
|
|
||||||
|
if (is_array($token_data) && isset($token_data['token'])) {
|
||||||
|
$this->token = $token_data['token'];
|
||||||
|
} elseif (is_string($token_data) && !empty($token_data)) {
|
||||||
|
$this->token = trim($token_data, '"');
|
||||||
|
} elseif (is_string($response) && !empty($response)) {
|
||||||
|
$this->token = trim($response, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->token)) {
|
||||||
|
throw new Exception("Token non ricevuto: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getToken()
|
||||||
|
{
|
||||||
|
if ($this->token === null) {
|
||||||
|
$this->authenticate();
|
||||||
|
}
|
||||||
|
return $this->token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($endpoint, $options = [])
|
||||||
|
{
|
||||||
|
$token = $this->getToken();
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$url = "{$this->baseUrl}/api/odata/{$endpoint}" . ($query ? '?' . $query : '');
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
"Authorization: Bearer {$token}",
|
||||||
|
"Accept: application/xml"
|
||||||
|
]);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
$log = fopen(__DIR__ . '/curl_request_debug_xml.log', 'w') ?: fopen('php://stderr', 'w');
|
||||||
|
curl_setopt($ch, CURLOPT_STDERR, $log);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$curl_error = curl_error($ch);
|
||||||
|
fclose($log);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false) {
|
||||||
|
throw new Exception("Errore nella richiesta: {$curl_error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($http_code !== 200) {
|
||||||
|
throw new Exception("Errore nel recupero dati: HTTP {$http_code}, Risposta: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica che la risposta sia XML
|
||||||
|
if (strpos($response, '<?xml') !== 0) {
|
||||||
|
throw new Exception("Risposta non valida: atteso formato XML, ricevuto: " . substr($response, 0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,6 @@ Content-Length: 51
|
|||||||
< strict-transport-security: max-age=2592000
|
< strict-transport-security: max-age=2592000
|
||||||
< x-powered-by: ASP.NET
|
< x-powered-by: ASP.NET
|
||||||
< x-content-type-options: nosniff
|
< x-content-type-options: nosniff
|
||||||
< date: Wed, 20 Aug 2025 15:35:19 GMT
|
< date: Fri, 29 Aug 2025 13:36:31 GMT
|
||||||
<
|
<
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
* Connection #0 to host 93.43.5.102 left intact
|
||||||
|
|||||||
@@ -10,16 +10,16 @@
|
|||||||
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
||||||
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
||||||
* using HTTP/2
|
* using HTTP/2
|
||||||
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues
|
||||||
* [HTTP/2] [1] [:method: GET]
|
* [HTTP/2] [1] [:method: GET]
|
||||||
* [HTTP/2] [1] [:scheme: https]
|
* [HTTP/2] [1] [:scheme: https]
|
||||||
* [HTTP/2] [1] [:authority: 93.43.5.102]
|
* [HTTP/2] [1] [:authority: 93.43.5.102]
|
||||||
* [HTTP/2] [1] [:path: /limsapi/api/odata/SchemaCustomField]
|
* [HTTP/2] [1] [:path: /limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues]
|
||||||
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NTcxMTMxOSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.jY0MCCCy94eGWlodWV1TPv2SeQ7me_Hf1MJmU6TbVik]
|
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NjQ4MTc5MSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.066odH6XJ_XK1D_w6xYBCXncA6Hx1AgFqsanfvKULyk]
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
* [HTTP/2] [1] [accept: application/json]
|
||||||
> GET /limsapi/api/odata/SchemaCustomField HTTP/2
|
> GET /limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues HTTP/2
|
||||||
Host: 93.43.5.102
|
Host: 93.43.5.102
|
||||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NTcxMTMxOSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.jY0MCCCy94eGWlodWV1TPv2SeQ7me_Hf1MJmU6TbVik
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NjQ4MTc5MSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.066odH6XJ_XK1D_w6xYBCXncA6Hx1AgFqsanfvKULyk
|
||||||
Accept: application/json
|
Accept: application/json
|
||||||
|
|
||||||
< HTTP/2 200
|
< HTTP/2 200
|
||||||
@@ -30,6 +30,6 @@ Accept: application/json
|
|||||||
< odata-version: 4.0
|
< odata-version: 4.0
|
||||||
< x-powered-by: ASP.NET
|
< x-powered-by: ASP.NET
|
||||||
< x-content-type-options: nosniff
|
< x-content-type-options: nosniff
|
||||||
< date: Wed, 20 Aug 2025 15:35:19 GMT
|
< date: Fri, 29 Aug 2025 13:36:33 GMT
|
||||||
<
|
<
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
* Connection #0 to host 93.43.5.102 left intact
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
* Trying 93.43.5.102:443...
|
|
||||||
* Connected to 93.43.5.102 (93.43.5.102) port 443
|
|
||||||
* ALPN: curl offers h2,http/1.1
|
|
||||||
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
|
|
||||||
* ALPN: server accepted h2
|
|
||||||
* Server certificate:
|
|
||||||
* subject: C=FR; ST=Île-de-France; O=Bureau Veritas; CN=bvcpsitaly-elims.it
|
|
||||||
* start date: Feb 17 00:00:00 2025 GMT
|
|
||||||
* expire date: Feb 17 23:59:59 2026 GMT
|
|
||||||
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
|
||||||
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
|
||||||
* using HTTP/2
|
|
||||||
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/authentication/authenticate
|
|
||||||
* [HTTP/2] [1] [:method: POST]
|
|
||||||
* [HTTP/2] [1] [:scheme: https]
|
|
||||||
* [HTTP/2] [1] [:authority: 93.43.5.102]
|
|
||||||
* [HTTP/2] [1] [:path: /limsapi/api/authentication/authenticate]
|
|
||||||
* [HTTP/2] [1] [content-type: application/json]
|
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
|
||||||
* [HTTP/2] [1] [content-length: 51]
|
|
||||||
> POST /limsapi/api/authentication/authenticate HTTP/2
|
|
||||||
Host: 93.43.5.102
|
|
||||||
Content-Type: application/json
|
|
||||||
Accept: application/json
|
|
||||||
Content-Length: 51
|
|
||||||
|
|
||||||
< HTTP/2 200
|
|
||||||
< cache-control: max-age=0
|
|
||||||
< content-type: application/json; charset=utf-8
|
|
||||||
< server: Microsoft-IIS/10.0
|
|
||||||
< strict-transport-security: max-age=2592000
|
|
||||||
< x-powered-by: ASP.NET
|
|
||||||
< x-content-type-options: nosniff
|
|
||||||
< date: Tue, 03 Jun 2025 15:07:55 GMT
|
|
||||||
<
|
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
* Trying 93.43.5.102:443...
|
|
||||||
* Connected to 93.43.5.102 (93.43.5.102) port 443
|
|
||||||
* ALPN: curl offers h2,http/1.1
|
|
||||||
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
|
|
||||||
* ALPN: server accepted h2
|
|
||||||
* Server certificate:
|
|
||||||
* subject: C=FR; ST=Île-de-France; O=Bureau Veritas; CN=bvcpsitaly-elims.it
|
|
||||||
* start date: Feb 17 00:00:00 2025 GMT
|
|
||||||
* expire date: Feb 17 23:59:59 2026 GMT
|
|
||||||
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
|
||||||
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
|
||||||
* using HTTP/2
|
|
||||||
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/Cliente
|
|
||||||
* [HTTP/2] [1] [:method: GET]
|
|
||||||
* [HTTP/2] [1] [:scheme: https]
|
|
||||||
* [HTTP/2] [1] [:authority: 93.43.5.102]
|
|
||||||
* [HTTP/2] [1] [:path: /limsapi/api/odata/Cliente]
|
|
||||||
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1OTY5MiwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.O60U9XXapZOj0U3GuOIU0eiwgcUkzXTW6Eqy5f6q9D8]
|
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
|
||||||
> GET /limsapi/api/odata/Cliente HTTP/2
|
|
||||||
Host: 93.43.5.102
|
|
||||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1OTY5MiwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.O60U9XXapZOj0U3GuOIU0eiwgcUkzXTW6Eqy5f6q9D8
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
< HTTP/2 200
|
|
||||||
< cache-control: max-age=0
|
|
||||||
< content-type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
|
|
||||||
< server: Microsoft-IIS/10.0
|
|
||||||
< strict-transport-security: max-age=2592000
|
|
||||||
< odata-version: 4.0
|
|
||||||
< x-powered-by: ASP.NET
|
|
||||||
< x-content-type-options: nosniff
|
|
||||||
< date: Tue, 03 Jun 2025 12:08:45 GMT
|
|
||||||
<
|
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
* Trying 93.43.5.102:443...
|
|
||||||
* Connected to 93.43.5.102 (93.43.5.102) port 443
|
|
||||||
* ALPN: curl offers h2,http/1.1
|
|
||||||
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
|
|
||||||
* ALPN: server accepted h2
|
|
||||||
* Server certificate:
|
|
||||||
* subject: C=FR; ST=Île-de-France; O=Bureau Veritas; CN=bvcpsitaly-elims.it
|
|
||||||
* start date: Feb 17 00:00:00 2025 GMT
|
|
||||||
* expire date: Feb 17 23:59:59 2026 GMT
|
|
||||||
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
|
||||||
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
|
||||||
* using HTTP/2
|
|
||||||
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/authentication/authenticate
|
|
||||||
* [HTTP/2] [1] [:method: POST]
|
|
||||||
* [HTTP/2] [1] [:scheme: https]
|
|
||||||
* [HTTP/2] [1] [:authority: iftm.it]
|
|
||||||
* [HTTP/2] [1] [:path: /limsapi/api/authentication/authenticate]
|
|
||||||
* [HTTP/2] [1] [content-type: application/json]
|
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
|
||||||
* [HTTP/2] [1] [user-agent: Mozilla/5.0 (compatible; PHP cURL)]
|
|
||||||
* [HTTP/2] [1] [content-length: 51]
|
|
||||||
> POST /limsapi/api/authentication/authenticate HTTP/2
|
|
||||||
Host: iftm.it
|
|
||||||
Content-Type: application/json
|
|
||||||
Accept: application/json
|
|
||||||
User-Agent: Mozilla/5.0 (compatible; PHP cURL)
|
|
||||||
Content-Length: 51
|
|
||||||
|
|
||||||
< HTTP/2 200
|
|
||||||
< cache-control: max-age=0
|
|
||||||
< content-type: application/json; charset=utf-8
|
|
||||||
< server: Microsoft-IIS/10.0
|
|
||||||
< strict-transport-security: max-age=2592000
|
|
||||||
< x-powered-by: ASP.NET
|
|
||||||
< x-content-type-options: nosniff
|
|
||||||
< date: Tue, 03 Jun 2025 10:19:09 GMT
|
|
||||||
<
|
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
HTTP Code: 200
|
|
||||||
Response: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1MTAyMSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.KntKk8Up-9owFjy7onziK2BfncEnSNhizyNX9S-QHaw"
|
|
||||||
|
|
||||||
HTTP Code: 200
|
|
||||||
Response: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1MTEyNSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.IWjzzBg0kQ3lq4aK2ByMlY7Bwzb7Qq-6ziXV8kkZ2J0"
|
|
||||||
|
|
||||||
HTTP Code: 200
|
|
||||||
Response: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1MTI2NSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.UgVz6PTF9dmbFYdgyRZS0TcI0pvLEIQ3yMjPiicF1vs"
|
|
||||||
|
|
||||||
HTTP Code: 200
|
|
||||||
Response: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1MTMwNywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.PolfU_FWuVMd-YfonBYTo0i0qIl6kn6nUkCWCEBvZuA"
|
|
||||||
|
|
||||||
HTTP Code: 200
|
|
||||||
Response: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1MTQ0OSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.CGZ-9KbMmW19JYTVGfjIcbNscSsGB4dwoHCJkHHs_4M"
|
|
||||||
|
|
||||||
HTTP Code: 200
|
|
||||||
Response: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk1MTc1MCwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.FCAm5sWed1Q-QiIsctMgSBfEd4sfN3kfVR3Mqd3XQz0"
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
* Trying 93.43.5.102:443...
|
|
||||||
* Connected to 93.43.5.102 (93.43.5.102) port 443
|
|
||||||
* ALPN: curl offers h2,http/1.1
|
|
||||||
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
|
|
||||||
* ALPN: server accepted h2
|
|
||||||
* Server certificate:
|
|
||||||
* subject: C=FR; ST=Île-de-France; O=Bureau Veritas; CN=bvcpsitaly-elims.it
|
|
||||||
* start date: Feb 17 00:00:00 2025 GMT
|
|
||||||
* expire date: Feb 17 23:59:59 2026 GMT
|
|
||||||
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
|
||||||
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
|
||||||
* using HTTP/2
|
|
||||||
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/Cliente(5860)?$expand=SchemiAbilitati
|
|
||||||
* [HTTP/2] [1] [:method: GET]
|
|
||||||
* [HTTP/2] [1] [:scheme: https]
|
|
||||||
* [HTTP/2] [1] [:authority: 93.43.5.102]
|
|
||||||
* [HTTP/2] [1] [:path: /limsapi/api/odata/Cliente(5860)?$expand=SchemiAbilitati]
|
|
||||||
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk3MDQ3NSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.vABzuZkQE9luU_uc4e18AYiM5c2Jnf-z1Q3sofbz6O0]
|
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
|
||||||
> GET /limsapi/api/odata/Cliente(5860)?$expand=SchemiAbilitati HTTP/2
|
|
||||||
Host: 93.43.5.102
|
|
||||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk3MDQ3NSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.vABzuZkQE9luU_uc4e18AYiM5c2Jnf-z1Q3sofbz6O0
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
< HTTP/2 200
|
|
||||||
< cache-control: max-age=0
|
|
||||||
< content-type: application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
|
|
||||||
< server: Microsoft-IIS/10.0
|
|
||||||
< strict-transport-security: max-age=2592000
|
|
||||||
< odata-version: 4.0
|
|
||||||
< x-powered-by: ASP.NET
|
|
||||||
< x-content-type-options: nosniff
|
|
||||||
< date: Tue, 03 Jun 2025 15:07:56 GMT
|
|
||||||
<
|
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
* Trying 93.43.5.102:443...
|
|
||||||
* Connected to 93.43.5.102 (93.43.5.102) port 443
|
|
||||||
* ALPN: curl offers h2,http/1.1
|
|
||||||
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
|
|
||||||
* ALPN: server accepted h2
|
|
||||||
* Server certificate:
|
|
||||||
* subject: C=FR; ST=Île-de-France; O=Bureau Veritas; CN=bvcpsitaly-elims.it
|
|
||||||
* start date: Feb 17 00:00:00 2025 GMT
|
|
||||||
* expire date: Feb 17 23:59:59 2026 GMT
|
|
||||||
* issuer: C=US; O=Corporation Service Company; CN=Corporation Service Company RSA OV SSL CA
|
|
||||||
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
|
|
||||||
* using HTTP/2
|
|
||||||
* [HTTP/2] [1] OPENED stream for https://93.43.5.102/limsapi/api/odata/Cliente(0)?$expand=SchemiAbilitati
|
|
||||||
* [HTTP/2] [1] [:method: GET]
|
|
||||||
* [HTTP/2] [1] [:scheme: https]
|
|
||||||
* [HTTP/2] [1] [:authority: 93.43.5.102]
|
|
||||||
* [HTTP/2] [1] [:path: /limsapi/api/odata/Cliente(0)?$expand=SchemiAbilitati]
|
|
||||||
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk2NTQ4MywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.oSwFJRuj0lDD7D6dOLIZWhn_Lzma0b38dLPEDIOMD7o]
|
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
|
||||||
> GET /limsapi/api/odata/Cliente(0)?$expand=SchemiAbilitati HTTP/2
|
|
||||||
Host: 93.43.5.102
|
|
||||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc0ODk2NTQ4MywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.oSwFJRuj0lDD7D6dOLIZWhn_Lzma0b38dLPEDIOMD7o
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
< HTTP/2 404
|
|
||||||
< cache-control: no-cache,no-store,max-age=0
|
|
||||||
< pragma: no-cache
|
|
||||||
< content-type: application/problem+json
|
|
||||||
< expires: -1
|
|
||||||
< server: Microsoft-IIS/10.0
|
|
||||||
< x-powered-by: ASP.NET
|
|
||||||
< x-content-type-options: nosniff
|
|
||||||
< date: Tue, 03 Jun 2025 13:44:44 GMT
|
|
||||||
<
|
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":4101,"message":"Tracking No. already exists."},"data":{"id":"9e85e85acd18a1c92d9fa1f6fede8a23","tracking_number":"750000810057432004040056","courier_code":"tnt-it"}}
|
|
||||||
HTTP Code: 400
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":4101,"message":"Tracking No. already exists."},"data":{"id":"9e85e85acd18a1c92d9fa1f6fede8a23","tracking_number":"750000810057432004040056","courier_code":"tnt-it"},"success":false,"http_code":400}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings?tracking_numbers=750000810057432004040056&courier_code=tnt-it
|
|
||||||
Request Data: []
|
|
||||||
Response: {"meta":{"code":200,"type":"Success","message":"The request was successful."},"data":[]}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Get Response: {"meta":{"code":200,"type":"Success","message":"The request was successful."},"data":[],"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":4101,"message":"Tracking No. already exists."},"data":{"id":"9e85e85acd18a1c92d9fa1f6fede8a23","tracking_number":"750000810057432004040056","courier_code":"tnt-it"}}
|
|
||||||
HTTP Code: 400
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":4101,"message":"Tracking No. already exists."},"data":{"id":"9e85e85acd18a1c92d9fa1f6fede8a23","tracking_number":"750000810057432004040056","courier_code":"tnt-it"},"success":false,"http_code":400}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/get?tracking_numbers=750000810057432004040056&courier_code=tnt-it
|
|
||||||
Request Data: []
|
|
||||||
Response: {"meta":{"code":200,"type":"Success","message":"The request was successful."},"data":[]}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Get Response: {"meta":{"code":200,"type":"Success","message":"The request was successful."},"data":[],"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":4101,"message":"Tracking No. already exists."},"data":{"id":"9e85e85acd18a1c92d9fa1f6fede8a23","tracking_number":"750000810057432004040056","courier_code":"tnt-it"}}
|
|
||||||
HTTP Code: 400
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":4101,"message":"Tracking No. already exists."},"data":{"id":"9e85e85acd18a1c92d9fa1f6fede8a23","tracking_number":"750000810057432004040056","courier_code":"tnt-it"},"success":false,"http_code":400}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/get?tracking_numbers=750000810057432004040056
|
|
||||||
Request Data: []
|
|
||||||
Response: {"meta":{"code":200,"type":"Success","message":"The request was successful."},"data":[]}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Get Response: {"meta":{"code":200,"type":"Success","message":"The request was successful."},"data":[],"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e85f77564ba2d1b2d35c7b28c72e62b","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-03-26T09:43:15+00:00","update_at":"2025-03-26T09:01:02+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}}}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e85f77564ba2d1b2d35c7b28c72e62b","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-03-26T09:43:15+00:00","update_at":"2025-03-26T09:01:02+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}},"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e8601d0116ffa9f4abe6fa609f27214","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-03-26T10:12:12+00:00","update_at":"2025-03-26T09:43:15+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}}}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e8601d0116ffa9f4abe6fa609f27214","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-03-26T10:12:12+00:00","update_at":"2025-03-26T09:43:15+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}},"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "75000",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"75000","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e88676cc0b94ee0270add7c597d0cb0","tracking_number":"75000","courier_code":"tnt-it","order_number":"75000","order_date":null,"created_at":"2025-03-27T14:47:59+00:00","update_at":null,"delivery_status":"pending","archived":"tracking","updating":true,"source":"API","destination_country":null,"destination_state":null,"destination_city":null,"origin_country":null,"origin_state":null,"origin_city":null,"tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":null,"service_code":null,"weight":null,"weight_kg":null,"product_type":null,"pieces":null,"dimension":null,"previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"pending002","status_info":null,"latest_event":null,"latest_checkpoint_time":null,"transit_time":0,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}}}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e88676cc0b94ee0270add7c597d0cb0","tracking_number":"75000","courier_code":"tnt-it","order_number":"75000","order_date":null,"created_at":"2025-03-27T14:47:59+00:00","update_at":null,"delivery_status":"pending","archived":"tracking","updating":true,"source":"API","destination_country":null,"destination_state":null,"destination_city":null,"origin_country":null,"origin_state":null,"origin_city":null,"tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":null,"service_code":null,"weight":null,"weight_kg":null,"product_type":null,"pieces":null,"dimension":null,"previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"pending002","status_info":null,"latest_event":null,"latest_checkpoint_time":null,"transit_time":0,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}},"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e8867d062b0ddfac8655e3d81b289af","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-03-27T14:49:04+00:00","update_at":"2025-03-26T10:12:12+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}}}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e8867d062b0ddfac8655e3d81b289af","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-03-27T14:49:04+00:00","update_at":"2025-03-26T10:12:12+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}},"success":true,"http_code":200}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "123",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"123","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":4110,"message":"The value of tracking_number is invalid."},"data":null}
|
|
||||||
HTTP Code: 400
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":4110,"message":"The value of tracking_number is invalid."},"data":null,"success":false,"http_code":400}
|
|
||||||
Encoded JSON Data: {
|
|
||||||
"tracking_number": "750000810057432004040056",
|
|
||||||
"courier_code": "tnt-it"
|
|
||||||
}
|
|
||||||
Request URL: https://api.trackingmore.com/v4/trackings/create
|
|
||||||
Request Data: {"tracking_number":"750000810057432004040056","courier_code":"tnt-it"}
|
|
||||||
Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e9652c58e37fc7c8c9b08e9f2eb8f8e","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-04-03T12:51:49+00:00","update_at":"2025-04-01T09:02:08+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}}}
|
|
||||||
HTTP Code: 200
|
|
||||||
Error:
|
|
||||||
Create Response: {"meta":{"code":200,"message":"Request response is successful"},"data":{"id":"9e9652c58e37fc7c8c9b08e9f2eb8f8e","tracking_number":"750000810057432004040056","courier_code":"tnt-it","order_number":"750000810057432004040056","order_date":null,"created_at":"2025-04-03T12:51:49+00:00","update_at":"2025-04-01T09:02:08+00:00","delivery_status":"delivered","archived":"tracking","updating":false,"source":"API","destination_country":"IT","destination_state":"MB","destination_city":"MEDA","origin_country":null,"origin_state":"BS","origin_city":"BRESCIA","tracking_postal_code":null,"tracking_ship_date":null,"tracking_destination_country":null,"tracking_origin_country":null,"tracking_key":null,"tracking_courier_account":null,"customer_name":null,"customer_email":null,"customer_sms":null,"recipient_postcode":null,"order_id":null,"title":null,"logistics_channel":null,"note":null,"label":null,"signed_by":"SIRONI","service_code":"Express","weight":"0,020","weight_kg":null,"product_type":null,"pieces":"1","dimension":"0,001","previously":null,"destination_track_number":null,"exchange_number":null,"scheduled_delivery_date":null,"scheduled_address":null,"substatus":"delivered003","status_info":null,"latest_event":"Spedizione consegnata,COMO,2025-03-25 11:12:00","latest_checkpoint_time":"2025-03-25T11:12:00","transit_time":1,"origin_info":{"courier_code":"tnt-it","courier_phone":"+39 199 803 868","weblink":"http:\/\/www.tnt.it\/","tracking_link":"https:\/\/www.tnt.it\/tracking\/Tracking.do","reference_number":"MY01818480","milestone_date":{"inforeceived_date":null,"pickup_date":"2025-03-24T17:35:00","outfordelivery_date":"2025-03-25T09:31:00","delivery_date":"2025-03-25T11:12:00","returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[{"checkpoint_date":"2025-03-25T11:12:00","checkpoint_delivery_status":"delivered","checkpoint_delivery_substatus":"delivered003","tracking_detail":"Spedizione consegnata","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T09:31:00","checkpoint_delivery_status":"pickup","checkpoint_delivery_substatus":"pickup001","tracking_detail":"La spedizione e' in consegna in data odierna","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-25T01:11:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' in transito","location":"COMO","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null},{"checkpoint_date":"2025-03-24T17:35:00","checkpoint_delivery_status":"transit","checkpoint_delivery_substatus":"transit001","tracking_detail":"La spedizione e' regolarmente partita","location":"BRESCIA","country_iso2":null,"state":null,"city":null,"zip":null,"raw_status":null}]},"destination_info":{"courier_code":null,"courier_phone":null,"weblink":null,"tracking_link":null,"reference_number":null,"milestone_date":{"inforeceived_date":null,"pickup_date":null,"outfordelivery_date":null,"delivery_date":null,"returning_date":null,"returned_date":null},"pickup_date":null,"departed_airport_date":null,"arrived_abroad_date":null,"customs_received_date":null,"trackinfo":[]}},"success":true,"http_code":200}
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
// Enable errors for debugging
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/delete_record_debug.log');
|
||||||
|
|
||||||
|
// Log iniziale
|
||||||
|
error_log("Inizio cancellazione record alle " . date('Y-m-d H:i:s'));
|
||||||
|
|
||||||
|
// Includi il file di configurazione del database
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
// Ricevi l'ID dalla richiesta POST
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
$iddatadb = isset($input['id']) ? intval($input['id']) : 0;
|
||||||
|
|
||||||
|
if ($iddatadb <= 0) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connessione al database
|
||||||
|
try {
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore di connessione al database: ' . $e->getMessage()]);
|
||||||
|
error_log("Errore di connessione al database: " . $e->getMessage());
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inizia una transazione
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Elimina i dettagli associati dal tavolo import_data_details
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM import_data_details WHERE id = ?");
|
||||||
|
$stmt->execute([$iddatadb]);
|
||||||
|
|
||||||
|
// Elimina il record principale dal tavolo datadb
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM datadb WHERE iddatadb = ?");
|
||||||
|
$stmt->execute([$iddatadb]);
|
||||||
|
|
||||||
|
// Verifica se il record è stato eliminato
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
$pdo->commit();
|
||||||
|
echo json_encode(['success' => true, 'message' => 'Record eliminato con successo']);
|
||||||
|
error_log("Record con iddatadb=$iddatadb eliminato con successo");
|
||||||
|
} else {
|
||||||
|
$pdo->rollBack();
|
||||||
|
http_response_code(404);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Record non trovato']);
|
||||||
|
error_log("Record con iddatadb=$iddatadb non trovato");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore durante la cancellazione: ' . $e->getMessage()]);
|
||||||
|
error_log("Errore durante la cancellazione del record con iddatadb=$iddatadb: " . $e->getMessage());
|
||||||
|
}
|
||||||
@@ -6,3 +6,8 @@
|
|||||||
2025-07-04 10:44:13 - 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"}
|
2025-07-04 10:44:13 - 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"}
|
||||||
2025-07-04 10:48:07 - 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"}
|
2025-07-04 10:48:07 - 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"}
|
||||||
2025-08-19 16:29:25 - 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"}
|
2025-08-19 16:29:25 - 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"}
|
||||||
|
2025-08-26 16:47:19 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
2025-08-26 16:48:15 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
2025-08-26 16:48:44 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
2025-08-26 16:49:24 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
2025-08-26 16:50:23 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Torna al livello di public
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
@@ -9,20 +9,30 @@ error_reporting(E_ALL);
|
|||||||
try {
|
try {
|
||||||
$api = VisualLimsApiClient::getInstance();
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
// ID del campo custom passato da GET oppure default
|
// მივიღოთ მრავლობითი field_ids
|
||||||
$customFieldId = isset($_GET['field_id']) && is_numeric($_GET['field_id']) ? intval($_GET['field_id']) : 156;
|
$fieldIds = [];
|
||||||
|
if (isset($_GET['field_ids'])) {
|
||||||
|
$fieldIds = array_filter(array_map('intval', explode(',', $_GET['field_ids'])));
|
||||||
|
}
|
||||||
|
|
||||||
// Endpoint con $expand per ottenere i valori
|
// თუ არ გადმოგვცეს -> ერთი default
|
||||||
$endpoint = "CustomField($customFieldId)?\$expand=CustomFieldsValues";
|
if (empty($fieldIds)) {
|
||||||
|
$fieldIds = [156];
|
||||||
|
}
|
||||||
|
|
||||||
// Recupera i dati dal server
|
$results = [];
|
||||||
$data = $api->get($endpoint);
|
|
||||||
|
|
||||||
// Salva la risposta in un file per debug
|
foreach ($fieldIds as $customFieldId) {
|
||||||
file_put_contents(__DIR__ . '/customfield_values_response.json', json_encode($data));
|
$endpoint = "CustomField($customFieldId)?\$expand=CustomFieldsValues";
|
||||||
|
$data = $api->get($endpoint);
|
||||||
|
|
||||||
// Output JSON al client
|
$results[$customFieldId] = $data['CustomFieldsValues'] ?? [];
|
||||||
echo json_encode($data);
|
}
|
||||||
|
|
||||||
|
// Debug ფაილი
|
||||||
|
file_put_contents(__DIR__ . '/customfield_values_response.json', json_encode($results));
|
||||||
|
|
||||||
|
echo json_encode($results);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClientXml.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/xml; charset=utf-8');
|
||||||
|
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$api = VisualLimsApiClientXml::getInstance();
|
||||||
|
|
||||||
|
// Endpoint per i metadata
|
||||||
|
$endpoint = '$metadata';
|
||||||
|
|
||||||
|
// Nessun parametro aggiuntivo necessario
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
// Debug: salva URL usato
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
$query = http_build_query($options);
|
||||||
|
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Chiamata API
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
// Salva il file XML in locale
|
||||||
|
file_put_contents(__DIR__ . '/metadata_response.xml', $data);
|
||||||
|
|
||||||
|
// Restituisci il contenuto XML
|
||||||
|
echo $data;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
|
||||||
|
http_response_code(500);
|
||||||
|
echo '<?xml version="1.0" encoding="utf-8"?><error>' . htmlspecialchars($e->getMessage()) . '</error>';
|
||||||
|
}
|
||||||
@@ -19,11 +19,11 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !i
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$template_id = intval($_POST['template_id']);
|
$template_id = intval($_POST['template_id']) ?? $_SESSION['template_id'];
|
||||||
$selected_rows = $_POST['selected_rows'];
|
$selected_rows = $_POST['selected_rows'] ?? $_SESSION['selected_rows'];
|
||||||
$columns = json_decode($_POST['columns'], true); // Header dell'XLS
|
$columns = json_decode($_POST['columns'], true) ?? $_SESSION['columns']; // Header dell'XLS
|
||||||
$rows = json_decode($_POST['rows'], true); // Dati dell'XLS
|
$rows = json_decode($_POST['rows'], true) ?? $_SESSION['rows']; // Dati dell'XLS
|
||||||
$newFilename = htmlspecialchars($_POST['filename']);
|
$newFilename = htmlspecialchars($_POST['filename']) ?? $_SESSION['filename'];
|
||||||
|
|
||||||
// Log dei dati ricevuti
|
// Log dei dati ricevuti
|
||||||
error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows));
|
error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows));
|
||||||
@@ -40,7 +40,7 @@ $pdo = $db->getConnection();
|
|||||||
$importReferenceCode = date('YmdHis') . '-' . uniqid();
|
$importReferenceCode = date('YmdHis') . '-' . uniqid();
|
||||||
|
|
||||||
// Recupera tutti i mapping dal template
|
// Recupera tutti i mapping dal template
|
||||||
$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id 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 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);
|
||||||
|
|
||||||
@@ -49,71 +49,17 @@ if (empty($allMappings)) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserisci le righe selezionate in datadb (solo campi generici con templateid)
|
// Trova il campo main_field
|
||||||
$insertedIds = [];
|
$mainFieldMapping = null;
|
||||||
foreach ($selected_rows as $rowIndex) {
|
foreach ($allMappings as $mapping) {
|
||||||
$row = $rows[$rowIndex];
|
if ($mapping['main_field'] == 1) {
|
||||||
$values = [
|
$mainFieldMapping = $mapping;
|
||||||
$template_id, // templateid
|
break;
|
||||||
$importReferenceCode, // importreferencecode
|
|
||||||
$newFilename, // filename_import
|
|
||||||
'i', // status
|
|
||||||
$user_id, // user_id
|
|
||||||
null, // limscode
|
|
||||||
date('Y-m-d') // importdate
|
|
||||||
];
|
|
||||||
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
|
||||||
$stmt = $pdo->prepare($sql);
|
|
||||||
$stmt->execute($values);
|
|
||||||
|
|
||||||
$iddatadb = $pdo->lastInsertId();
|
|
||||||
$insertedIds[] = $iddatadb;
|
|
||||||
|
|
||||||
// Inserisci tutti i campi (automatici e manuali) in import_data_details
|
|
||||||
foreach ($allMappings as $mapping) {
|
|
||||||
$fieldValue = null;
|
|
||||||
if (!$mapping['is_manual']) { // Campi automatici dall'XLS
|
|
||||||
$excelColumn = trim($mapping['excel_column']);
|
|
||||||
$excelColumnIndex = array_search($excelColumn, array_map('trim', $columns));
|
|
||||||
if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') {
|
|
||||||
$fieldValue = $row[$excelColumnIndex];
|
|
||||||
error_log("Found Excel column '$excelColumn' at index $excelColumnIndex, value: " . var_export($fieldValue, true));
|
|
||||||
} else {
|
|
||||||
$fieldValue = $mapping['manual_default'] ?? '';
|
|
||||||
error_log("Excel column '$excelColumn' not found or empty, using default: " . var_export($fieldValue, true));
|
|
||||||
}
|
|
||||||
switch ($mapping['data_type']) {
|
|
||||||
case 'INT':
|
|
||||||
$fieldValue = is_numeric($fieldValue) ? (int)$fieldValue : ($mapping['manual_default'] ?? 0);
|
|
||||||
break;
|
|
||||||
case 'DATE':
|
|
||||||
$fieldValue = !empty($fieldValue) ? date('Y-m-d', strtotime($fieldValue)) : ($mapping['manual_default'] === 'today' ? date('Y-m-d') : ($mapping['manual_default'] ?? ''));
|
|
||||||
break;
|
|
||||||
case 'CHAR':
|
|
||||||
$fieldValue = !empty($fieldValue) ? substr((string)$fieldValue, 0, 1) : ($mapping['manual_default'] ?? '');
|
|
||||||
break;
|
|
||||||
case 'Testo':
|
|
||||||
case 'VARCHAR':
|
|
||||||
default:
|
|
||||||
$fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? '');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else { // Campi manuali
|
|
||||||
$fieldValue = $mapping['manual_default'] ?? '';
|
|
||||||
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
|
|
||||||
$fieldValue = date('Y-m-d');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) {
|
|
||||||
error_log("Required field missing for mapping ID: " . $mapping['id'] . ", field: " . $mapping['field_label']);
|
|
||||||
}
|
|
||||||
error_log("Inserting into import_data_details - Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true) . ", Is Manual: " . $mapping['is_manual'] . ", Excel Column: " . ($mapping['excel_column'] ?? 'N/A') . ", Manual Default: " . ($mapping['manual_default'] ?? 'N/A'));
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)");
|
|
||||||
$stmt->execute([$iddatadb, $mapping['id'], $fieldValue]);
|
|
||||||
error_log("Inserted into import_data_details for ID $iddatadb, Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids'];
|
||||||
|
|
||||||
// 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
|
||||||
@@ -152,6 +98,11 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2Lw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2Lw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
<style>
|
<style>
|
||||||
|
.cell-changed {
|
||||||
|
background-color: #fff3b0 !important; /* რბილი ყვითელი */
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
/* Colori pastello per input/select */
|
/* Colori pastello per input/select */
|
||||||
input.auto-input,
|
input.auto-input,
|
||||||
select.auto-input {
|
select.auto-input {
|
||||||
@@ -189,6 +140,32 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
/* Colore scuro per contrasto */
|
/* Colore scuro per contrasto */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stili per i badge di stato */
|
||||||
|
.status-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 12px;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-i {
|
||||||
|
background-color: #ffc107;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-P {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-l {
|
||||||
|
background-color: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* Stili esistenti rimangono invariati */
|
/* Stili esistenti rimangono invariati */
|
||||||
.grid-container {
|
.grid-container {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@@ -221,7 +198,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
.grid-header,
|
.grid-header,
|
||||||
.grid-cell {
|
.grid-cell {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 100px;
|
min-width: 70px;
|
||||||
padding: 12px 15px;
|
padding: 12px 15px;
|
||||||
border-right: 1px solid #dee2e6;
|
border-right: 1px solid #dee2e6;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -397,6 +374,28 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
border-color: #80bdff;
|
border-color: #80bdff;
|
||||||
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
|
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stile per l'header dei pulsanti combinati */
|
||||||
|
.grid-cell.button-cell,
|
||||||
|
.grid-header.button-header {
|
||||||
|
min-width: 210px !important;
|
||||||
|
flex: 0 0 210px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
padding: 6px 8px;
|
||||||
|
margin-right: 5px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 35px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flash-success {
|
||||||
|
background-color: #d4edda !important;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
@@ -407,13 +406,20 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<?php //include('top_stat_widget.php');
|
<div class="mb-3 text">
|
||||||
?>
|
<a href="historical_trf.php?id=<?= $template_id ?>&status=i" class="btn btn-warning me-2">Imported (i)</a>
|
||||||
|
<a href="historical_trf.php?id=<?= $template_id ?>&status=P" class="btn btn-primary me-2">In Progress (P)</a>
|
||||||
|
<a href="historical_trf.php?id=<?= $template_id ?>&status=l" class="btn btn-success">To LIMS (l)</a>
|
||||||
|
</div>
|
||||||
<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>
|
||||||
<h6 class="mb-0">Modifica Dati Importati</h6>
|
<h6 class="mb-0">Modifica Dati Importati</h6>
|
||||||
|
<div id="unsavedChanges" style="display:none; color: red; font-weight: bold; margin:10px 0;">
|
||||||
|
⚠️ 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>
|
||||||
@@ -422,38 +428,59 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<div class="grid-container">
|
<div class="grid-container">
|
||||||
<!-- Riga superiore per gli input dei campi manuali -->
|
<!-- Riga superiore per gli input dei campi manuali -->
|
||||||
<div class="grid-top">
|
<div class="grid-top">
|
||||||
<div class="grid-cell" style="flex: 0 0 100px;"></div> <!-- Save -->
|
<div class="grid-cell button-cell" style="flex: 0 0 210px;"></div> <!-- Actions -->
|
||||||
<div class="grid-cell" style="flex: 0 0 100px;"></div> <!-- Photos -->
|
<?php if ($mainFieldMapping): ?>
|
||||||
<div class="grid-cell" style="flex: 0 0 100px;"></div> <!-- Parts -->
|
<div class="grid-cell" style="flex: 0 0 150px;">
|
||||||
<div class="grid-cell" style="flex: 0 0 150px;"></div> <!-- importreferencecode -->
|
<?php
|
||||||
|
$fieldValue = $mainFieldMapping['manual_default'] ?? '';
|
||||||
|
if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today') {
|
||||||
|
$fieldValue = date('Y-m-d');
|
||||||
|
}
|
||||||
|
$inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
|
||||||
|
if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
|
||||||
|
if ($mainFieldMapping['data_type'] === 'SceltaMultipla') {
|
||||||
|
echo "<select class='custom-field dropdown-select $inputClass' data-column='main_field' data-field-id='{$mainFieldMapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
|
||||||
|
echo "<option value=''>Seleziona...</option>";
|
||||||
|
echo "</select>";
|
||||||
|
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
|
||||||
|
} elseif ($mainFieldMapping['data_type'] === 'DATE') {
|
||||||
|
echo "<input type='date' class='custom-field $inputClass' data-column='main_field' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
|
||||||
|
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
|
||||||
|
} elseif ($mainFieldMapping['data_type'] === 'INT') {
|
||||||
|
echo "<input type='number' class='custom-field $inputClass' data-column='main_field' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
|
||||||
|
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
|
||||||
|
} else {
|
||||||
|
echo "<input type='text' class='custom-field $inputClass' data-column='main_field' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ">";
|
||||||
|
echo "<button type='button' class='propagate-btn' data-column='main_field'><i class='fas fa-arrow-down'></i></button>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="grid-cell" style="flex: 0 0 150px;"></div> <!-- status -->
|
||||||
<?php
|
<?php
|
||||||
$fixedColumns = ['filename_import', 'status', 'importdate'];
|
// Campi automatici (is_manual = 0) escluso main_field
|
||||||
foreach ($fixedColumns as $col) {
|
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
|
|
||||||
}
|
|
||||||
// Campi automatici (is_manual = 0) - Solo SceltaMultipla ha campo e propagazione
|
|
||||||
$autoIndex = 0;
|
$autoIndex = 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if (!$mapping['is_manual']) {
|
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
$inputClass = 'auto-input';
|
$inputClass = 'auto-input';
|
||||||
if ($mapping['is_required']) $inputClass .= ' required-input';
|
if ($mapping['is_required']) $inputClass .= ' required-input';
|
||||||
if ($mapping['data_type'] === 'SceltaMultipla') {
|
if ($mapping['data_type'] === 'SceltaMultipla') {
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
|
||||||
echo "<select class='custom-field dropdown-select $inputClass' data-column='auto_$autoIndex' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
echo "<select class='custom-field dropdown-select $inputClass' data-column='auto_$autoIndex' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
||||||
echo "<option value=''>Seleziona...</option>";
|
echo "<option value=''>Seleziona...</option>";
|
||||||
echo "</select>";
|
echo "</select>";
|
||||||
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' style='flex: 0 0 150px;'></div>"; // Nessun input per altri tipi
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
|
||||||
}
|
}
|
||||||
$autoIndex++;
|
$autoIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Campi manuali (is_manual = 1) con propagate-btn - Rimane invariato
|
// Campi manuali (is_manual = 1) escluso main_field
|
||||||
$manualIndex = 0;
|
$manualIndex = 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if ($mapping['is_manual']) {
|
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
$fieldValue = $mapping['manual_default'] ?? '';
|
$fieldValue = $mapping['manual_default'] ?? '';
|
||||||
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
|
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
|
||||||
$fieldValue = date('Y-m-d');
|
$fieldValue = date('Y-m-d');
|
||||||
@@ -462,10 +489,9 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
if ($mapping['is_required']) $inputClass .= ' required-input';
|
if ($mapping['is_required']) $inputClass .= ' required-input';
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
|
||||||
if ($mapping['data_type'] === 'SceltaMultipla') {
|
if ($mapping['data_type'] === 'SceltaMultipla') {
|
||||||
echo "<select class='custom-field dropdown-select $inputClass' data-column='manual_$manualIndex' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
echo "<select class='custom-field dropdown-select $inputClass' data-column='manual_$manualIndex' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
||||||
echo "<option value=''>Seleziona...</option>";
|
echo "<option value=''>Seleziona...</option>";
|
||||||
echo "</select>";
|
echo "</select>";
|
||||||
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex'><i class='fas fa-arrow-down'></i></button>";
|
|
||||||
} elseif ($mapping['data_type'] === 'DATE') {
|
} elseif ($mapping['data_type'] === 'DATE') {
|
||||||
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
||||||
} elseif ($mapping['data_type'] === 'INT') {
|
} elseif ($mapping['data_type'] === 'INT') {
|
||||||
@@ -480,79 +506,96 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
}
|
}
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>"; // AWB
|
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>"; // AWB
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>"; // Tracking Info
|
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>"; // Tracking Info
|
||||||
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // importreferencecode
|
||||||
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // filename_import
|
||||||
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // importdate
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Header della tabella -->
|
<!-- Header della tabella -->
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="grid-header" style="flex: 0 0 100px;">Save</div>
|
<div class="grid-header button-header" style="flex: 0 0 210px;">Actions</div>
|
||||||
<div class="grid-header" style="flex: 0 0 100px;">Photos</div>
|
<?php if ($mainFieldMapping): ?>
|
||||||
<div class="grid-header" style="flex: 0 0 100px;">Parts</div>
|
<div class="grid-header" data-index="1" style="flex: 0 0 150px; position: relative;">
|
||||||
<div class="grid-header" data-index="3" style="flex: 0 0 150px; position: relative;">Import Reference Code<div class="resizer"></div>
|
<?= htmlspecialchars($mainFieldMapping['field_label']) ?>
|
||||||
|
<div class="resizer"></div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="grid-header" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 150px; position: relative;">Status<div class="resizer"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
$headerIndex = 4;
|
$headerIndex = $mainFieldMapping ? 3 : 2;
|
||||||
foreach ($fixedColumns as $col) {
|
|
||||||
$displayName = $slugMapping[$col] ?? $col;
|
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>$displayName<div class='resizer'></div></div>";
|
|
||||||
$headerIndex++;
|
|
||||||
}
|
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if (!$mapping['is_manual']) {
|
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
|
||||||
$headerIndex++;
|
$headerIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if ($mapping['is_manual']) {
|
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
|
||||||
$headerIndex++;
|
$headerIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 200px; position: relative;'>AWB Number<div class='resizer'></div></div>";
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 200px; position: relative;'>AWB Number<div class='resizer'></div></div>";
|
||||||
echo "<div class='grid-header' data-index='" . ($headerIndex + 1) . "' style='flex: 0 0 250px; position: relative;'>Tracking Info<div class='resizer'></div></div>";
|
$headerIndex++;
|
||||||
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 250px; position: relative;'>Tracking Info<div class='resizer'></div></div>";
|
||||||
|
$headerIndex++;
|
||||||
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>Import Reference Code<div class='resizer'></div></div>";
|
||||||
|
$headerIndex++;
|
||||||
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . ($slugMapping['filename_import'] ?? 'filename_import') . "<div class='resizer'></div></div>";
|
||||||
|
$headerIndex++;
|
||||||
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . ($slugMapping['importdate'] ?? 'importdate') . "<div class='resizer'></div></div>";
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Righe della tabella -->
|
<!-- Righe della tabella -->
|
||||||
<?php foreach ($importedData as $index => $row): ?>
|
<?php foreach ($importedData as $index => $row): ?>
|
||||||
<div class="grid-row" data-id="<?= $row['iddatadb'] ?>">
|
<div class="grid-row" data-id="<?= $row['iddatadb'] ?>">
|
||||||
<div class="grid-cell" style="flex: 0 0 100px; position: relative;">
|
<div class="grid-cell button-cell" style="flex: 0 0 210px; position: relative;">
|
||||||
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #28a745; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; width: 100%; box-sizing: border-box;"><i class="fas fa-save"></i></button>
|
<button type="button" class="export-lims-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Export to LIMS" style="background: #eb0b0bff; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-upload"></i></button>
|
||||||
|
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" title="Save" style="background: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-save"></i></button>
|
||||||
|
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Photos" style="background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-camera"></i></button>
|
||||||
|
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" title="Parts" style="background: #ffc107; color: white; border: none; border-radius: 5px; cursor: pointer;"><i class="fas fa-puzzle-piece"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-cell" style="flex: 0 0 100px; position: relative;">
|
<?php if ($mainFieldMapping): ?>
|
||||||
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #007bff; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; width: 100%; box-sizing: border-box;"><i class="fas fa-camera"></i></button>
|
<?php
|
||||||
</div>
|
$detail = array_filter($manualDetails, fn($d) => $d['mapping_id'] == $mainFieldMapping['id'] && $d['datadb_id'] == $row['iddatadb']);
|
||||||
<div class="grid-cell" style="flex: 0 0 100px; position: relative;">
|
$detail = reset($detail) ?: ['field_value' => $mainFieldMapping['manual_default']];
|
||||||
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ffc107; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; width: 100%; box-sizing: border-box;"><i class="fas fa-puzzle-piece"></i></button>
|
$fieldValue = $detail['field_value'] ?? $mainFieldMapping['manual_default'] ?? '';
|
||||||
|
if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today' && empty($fieldValue)) {
|
||||||
|
$fieldValue = date('Y-m-d');
|
||||||
|
}
|
||||||
|
$requiredClass = ($mainFieldMapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : '';
|
||||||
|
$inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
|
||||||
|
if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
|
||||||
|
?>
|
||||||
|
<div class="grid-cell editable-cell <?= $requiredClass ?>" data-col="main_field" data-row="<?= $index ?>" data-index="1" style="flex: 0 0 150px;">
|
||||||
|
<?php if ($mainFieldMapping['data_type'] === 'SceltaMultipla'): ?>
|
||||||
|
<select name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" class="cell-input dropdown-select <?= $inputClass ?>" data-mapping-id="<?= $mainFieldMapping['id'] ?>" data-field-id="<?= $mainFieldMapping['field_id'] ?>" data-selected-value="<?= htmlspecialchars($fieldValue) ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
|
||||||
|
<option value="">Seleziona...</option>
|
||||||
|
</select>
|
||||||
|
<?php elseif ($mainFieldMapping['data_type'] === 'DATE'): ?>
|
||||||
|
<input type="date" name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" value="<?= htmlspecialchars($fieldValue) ?>" class="cell-input <?= $inputClass ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
|
||||||
|
<?php elseif ($mainFieldMapping['data_type'] === 'INT'): ?>
|
||||||
|
<input type="number" name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" value="<?= htmlspecialchars($fieldValue) ?>" class="cell-input <?= $inputClass ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
|
||||||
|
<?php else: ?>
|
||||||
|
<input type="text" name="rows[<?= $index ?>][details][<?= $mainFieldMapping['id'] ?>][field_value]" value="<?= htmlspecialchars($fieldValue) ?>" class="cell-input <?= $inputClass ?>" <?= $mainFieldMapping['is_required'] ? 'required' : '' ?>>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="grid-cell editable-cell" data-col="status" data-row="<?= $index ?>" data-index="<?= $mainFieldMapping ? 2 : 1 ?>" style="flex: 0 0 150px;">
|
||||||
|
<span class="status-badge status-<?= htmlspecialchars($row['status'] ?? 'i') ?>">
|
||||||
|
<?= htmlspecialchars($row['status'] === 'i' ? 'Imported' : ($row['status'] === 'P' ? 'In Progress' : 'To LIMS')) ?>
|
||||||
|
</span>
|
||||||
|
<input type="hidden" name="rows[<?= $index ?>][status]" value="<?= htmlspecialchars($row['status'] ?? 'i') ?>">
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
$cellIndex = 3; // Inizia dopo importreferencecode
|
$cellIndex = $mainFieldMapping ? 3 : 2;
|
||||||
echo "<div class='grid-cell' data-col='importreferencecode' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
|
|
||||||
echo "<span>" . htmlspecialchars($row['importreferencecode']) . "</span>";
|
|
||||||
echo "<input type='hidden' name='rows[$index][importreferencecode]' value='" . htmlspecialchars($row['importreferencecode']) . "'>";
|
|
||||||
echo "</div>";
|
|
||||||
$cellIndex++;
|
|
||||||
foreach ($fixedColumns as $col) {
|
|
||||||
$value = $row[$col] ?? '';
|
|
||||||
echo "<div class='grid-cell editable-cell' data-col='$col' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
|
|
||||||
if ($col === 'importdate') {
|
|
||||||
echo "<span>" . htmlspecialchars($value) . "</span>";
|
|
||||||
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value) . "'>";
|
|
||||||
} elseif ($col === 'filename_import') {
|
|
||||||
echo "<a href='imported_trf/" . htmlspecialchars($value) . "' target='_blank'>File</a>";
|
|
||||||
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value) . "'>";
|
|
||||||
} elseif ($col === 'status') {
|
|
||||||
echo "<span class='status-display status-" . htmlspecialchars($value ?? 'i') . "'>" . htmlspecialchars($value === 'i' ? 'Imported' : ($value === 'P' ? 'Progress' : 'LIMS')) . "</span>";
|
|
||||||
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value ?? 'i') . "'>";
|
|
||||||
}
|
|
||||||
echo "</div>";
|
|
||||||
$cellIndex++;
|
|
||||||
}
|
|
||||||
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
|
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
|
||||||
$autoIndex = 0;
|
$autoIndex = 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if (!$mapping['is_manual']) {
|
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
$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'] ?? '';
|
||||||
@@ -561,7 +604,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
if ($mapping['is_required']) $inputClass .= ' required-input';
|
if ($mapping['is_required']) $inputClass .= ' required-input';
|
||||||
echo "<div class='grid-cell editable-cell $requiredClass' data-col='auto_$autoIndex' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
|
echo "<div class='grid-cell editable-cell $requiredClass' data-col='auto_$autoIndex' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
|
||||||
if ($mapping['data_type'] === 'SceltaMultipla') {
|
if ($mapping['data_type'] === 'SceltaMultipla') {
|
||||||
echo "<select name='rows[$index][details][{$mapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mapping['id']}' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
echo "<select name='rows[$index][details][{$mapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mapping['id']}' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
||||||
echo "<option value=''>Seleziona...</option>";
|
echo "<option value=''>Seleziona...</option>";
|
||||||
echo "</select>";
|
echo "</select>";
|
||||||
} elseif ($mapping['data_type'] === 'DATE') {
|
} elseif ($mapping['data_type'] === 'DATE') {
|
||||||
@@ -578,7 +621,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
}
|
}
|
||||||
$manualIndex = 0;
|
$manualIndex = 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if ($mapping['is_manual']) {
|
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
$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'] ?? '';
|
||||||
@@ -590,7 +633,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
if ($mapping['is_required']) $inputClass .= ' required-input';
|
if ($mapping['is_required']) $inputClass .= ' required-input';
|
||||||
echo "<div class='grid-cell editable-cell $requiredClass' data-col='manual_$manualIndex' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
|
echo "<div class='grid-cell editable-cell $requiredClass' data-col='manual_$manualIndex' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
|
||||||
if ($mapping['data_type'] === 'SceltaMultipla') {
|
if ($mapping['data_type'] === 'SceltaMultipla') {
|
||||||
echo "<select name='rows[$index][details][{$mapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mapping['id']}' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
echo "<select name='rows[$index][details][{$mapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mapping['id']}' data-field-id='{$mapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ">";
|
||||||
echo "<option value=''>Seleziona...</option>";
|
echo "<option value=''>Seleziona...</option>";
|
||||||
echo "</select>";
|
echo "</select>";
|
||||||
} elseif ($mapping['data_type'] === 'DATE') {
|
} elseif ($mapping['data_type'] === 'DATE') {
|
||||||
@@ -621,6 +664,24 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<span class="tracking-result">Shipment Info</span>
|
<span class="tracking-result">Shipment Info</span>
|
||||||
<input type="hidden" name="rows[<?= $index ?>][tracking_info]" class="tracking-hidden">
|
<input type="hidden" name="rows[<?= $index ?>][tracking_info]" class="tracking-hidden">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid-cell" data-col="importreferencecode" data-row="<?= $index ?>" data-index="<?= $cellIndex ?>" style="flex: 0 0 150px;">
|
||||||
|
<span><?= htmlspecialchars($row['importreferencecode']) ?></span>
|
||||||
|
<input type="hidden" name="rows[<?= $index ?>][importreferencecode]" value="<?= htmlspecialchars($row['importreferencecode']) ?>">
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$cellIndex++;
|
||||||
|
?>
|
||||||
|
<div class="grid-cell editable-cell" data-col="filename_import" data-row="<?= $index ?>" data-index="<?= $cellIndex ?>" style="flex: 0 0 150px;">
|
||||||
|
<a href="imported_trf/<?= htmlspecialchars($row['filename_import']) ?>" target="_blank">File</a>
|
||||||
|
<input type="hidden" name="rows[<?= $index ?>][filename_import]" value="<?= htmlspecialchars($row['filename_import']) ?>">
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$cellIndex++;
|
||||||
|
?>
|
||||||
|
<div class="grid-cell editable-cell" data-col="importdate" data-row="<?= $index ?>" data-index="<?= $cellIndex ?>" style="flex: 0 0 150px;">
|
||||||
|
<span><?= htmlspecialchars($row['importdate']) ?></span>
|
||||||
|
<input type="hidden" name="rows[<?= $index ?>][importdate]" value="<?= htmlspecialchars($row['importdate']) ?>">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
@@ -640,6 +701,91 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<script src="photos.js"></script>
|
<script src="photos.js"></script>
|
||||||
<script src="parts.js"></script>
|
<script src="parts.js"></script>
|
||||||
<script src="tracking.js"></script>
|
<script src="tracking.js"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const inputs = document.querySelectorAll(".cell-input, .dropdown-select, .carrier-select, .awb-input");
|
||||||
|
const unsavedDiv = document.getElementById("unsavedChanges");
|
||||||
|
const changedList = document.getElementById("changedFields");
|
||||||
|
|
||||||
|
let hasChanges = false;
|
||||||
|
let changedFields = {}; // { rowIndex: [fieldNames...] }
|
||||||
|
|
||||||
|
function renderChangedList() {
|
||||||
|
changedList.innerHTML = "";
|
||||||
|
|
||||||
|
Object.keys(changedFields).forEach(rowIndex => {
|
||||||
|
const fields = changedFields[rowIndex];
|
||||||
|
if (fields.length > 0) {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.textContent = `Row ${parseInt(rowIndex) + 1}: ${fields.join(", ")}`;
|
||||||
|
changedList.appendChild(li);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
unsavedDiv.style.display = Object.keys(changedFields).length > 0 ? "block" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.forEach(el => {
|
||||||
|
el.addEventListener("change", () => {
|
||||||
|
hasChanges = true;
|
||||||
|
|
||||||
|
const gridCell = el.closest(".grid-cell");
|
||||||
|
const colIndex = gridCell?.dataset.index;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowIndex !== undefined) {
|
||||||
|
if (!changedFields[rowIndex]) {
|
||||||
|
changedFields[rowIndex] = [];
|
||||||
|
}
|
||||||
|
if (!changedFields[rowIndex].includes(label)) {
|
||||||
|
changedFields[rowIndex].push(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
// highlight მხოლოდ ეს კონკრეტული cell
|
||||||
|
gridCell.classList.add("cell-changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderChangedList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll(".save-btn").forEach(btn => {
|
||||||
|
btn.addEventListener("click", () => {
|
||||||
|
const rowIndex = btn.dataset.row;
|
||||||
|
|
||||||
|
if (rowIndex !== undefined && changedFields[rowIndex]) {
|
||||||
|
delete changedFields[rowIndex]; // წავშალოთ კონკრეტული row
|
||||||
|
renderChangedList();
|
||||||
|
|
||||||
|
// ამოვშალოთ cell highlight იმ row-ში
|
||||||
|
document.querySelectorAll(`.grid-cell[data-row="${rowIndex}"]`)
|
||||||
|
.forEach(cell => cell.classList.remove("cell-changed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// თუ აღარაფერია შესანახი → false
|
||||||
|
if (Object.keys(changedFields).length === 0) {
|
||||||
|
hasChanges = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("beforeunload", function(e) {
|
||||||
|
if (hasChanges) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.returnValue = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
const inputs = document.querySelectorAll('.cell-input');
|
const inputs = document.querySelectorAll('.cell-input');
|
||||||
@@ -666,6 +812,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
formData.append(name, input.value);
|
formData.append(name, input.value);
|
||||||
});
|
});
|
||||||
formData.append('iddatadb', iddatadb);
|
formData.append('iddatadb', iddatadb);
|
||||||
|
formData.append('mapping', JSON.stringify(<?= json_encode($allMappings) ?>));
|
||||||
|
|
||||||
fetch('save_edited_row.php', {
|
fetch('save_edited_row.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -681,6 +828,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
cell.classList.add('flash-success');
|
cell.classList.add('flash-success');
|
||||||
});
|
});
|
||||||
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
|
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
|
||||||
|
alert('Salvataggio avvenuto con successo!');
|
||||||
} else {
|
} else {
|
||||||
alert('Errore durante il salvataggio: ' + data.message);
|
alert('Errore durante il salvataggio: ' + data.message);
|
||||||
}
|
}
|
||||||
@@ -692,14 +840,13 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
||||||
propagateButtons.forEach(button => {
|
propagateButtons.forEach(button => {
|
||||||
button.addEventListener('click', function() {
|
button.addEventListener('click', function() {
|
||||||
const columnIndex = this.getAttribute('data-column').replace('manual_', '');
|
const column = this.getAttribute('data-column');
|
||||||
const input = this.previousElementSibling;
|
const input = this.previousElementSibling;
|
||||||
const value = input.value;
|
const value = input.value;
|
||||||
|
|
||||||
// Trova la colonna target nella griglia superiore e propaga solo verticalmente
|
|
||||||
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
||||||
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
||||||
cell.querySelector('.propagate-btn') === button
|
cell.querySelector('.propagate-btn[data-column="' + column + '"]')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (targetTopIndex !== -1) {
|
if (targetTopIndex !== -1) {
|
||||||
@@ -709,9 +856,11 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
if (cells.length > targetTopIndex) {
|
if (cells.length > targetTopIndex) {
|
||||||
const targetInput = cells[targetTopIndex].querySelector('input, select');
|
const targetInput = cells[targetTopIndex].querySelector('input, select');
|
||||||
if (targetInput) {
|
if (targetInput) {
|
||||||
if (targetInput.type === 'date') targetInput.value = value;
|
targetInput.value = value;
|
||||||
else if (targetInput.tagName === 'SELECT') targetInput.value = value;
|
if (targetInput.tagName === 'SELECT') {
|
||||||
else targetInput.value = value;
|
const event = new Event('change');
|
||||||
|
targetInput.dispatchEvent(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -756,75 +905,125 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<!-- script dropdonw senza overlay -->
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
// Oggetto per memorizzare i dati delle tendine recuperati
|
|
||||||
const dropdownData = {};
|
const dropdownData = {};
|
||||||
|
|
||||||
async function populateDropdowns() {
|
async function populateDropdowns() {
|
||||||
const dropdowns = document.querySelectorAll('.dropdown-select');
|
const dropdowns = document.querySelectorAll('.dropdown-select');
|
||||||
if (dropdowns.length === 0) return;
|
if (dropdowns.length === 0) return;
|
||||||
|
|
||||||
// Recupera i dati solo per i field_id univoci
|
const uniqueFieldIds = [
|
||||||
const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId);
|
...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))
|
||||||
for (const fieldId of uniqueFieldIds) {
|
].filter(fieldId => fieldId);
|
||||||
if (!dropdownData[fieldId]) {
|
|
||||||
try {
|
const missingFieldIds = uniqueFieldIds.filter(fieldId => !dropdownData[fieldId]);
|
||||||
const response = await fetch(`get_customfield_values.php?field_id=${fieldId}`);
|
|
||||||
const data = await response.json();
|
if (missingFieldIds.length > 0) {
|
||||||
if (data.error) {
|
try {
|
||||||
console.error('Errore per field_id', fieldId, ':', data.error);
|
const response = await fetch(
|
||||||
continue;
|
`get_customfield_values.php?field_ids=${missingFieldIds.join(",")}`
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
console.error("Errore fetch multiplo:", data.error);
|
||||||
|
} else {
|
||||||
|
for (const fieldId of Object.keys(data)) {
|
||||||
|
dropdownData[fieldId] = data[fieldId] || [];
|
||||||
}
|
}
|
||||||
dropdownData[fieldId] = data.CustomFieldsValues || [];
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Errore nel fetch per field_id', fieldId, ':', error);
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Errore generale nel fetch multiplo:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Popola tutti i dropdown con i dati recuperati
|
|
||||||
dropdowns.forEach(dropdown => {
|
dropdowns.forEach(dropdown => {
|
||||||
const fieldId = dropdown.getAttribute('data-field-id');
|
const fieldId = dropdown.getAttribute('data-field-id');
|
||||||
|
const selectedValue = dropdown.getAttribute('data-selected-value') || '';
|
||||||
|
const currentValue = dropdown.value; // Preserva il valore corrente
|
||||||
|
|
||||||
if (!fieldId || !dropdownData[fieldId]) {
|
if (!fieldId || !dropdownData[fieldId]) {
|
||||||
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pulisci opzioni esistenti
|
|
||||||
dropdown.innerHTML = '<option value="">Seleziona...</option>';
|
dropdown.innerHTML = '<option value="">Seleziona...</option>';
|
||||||
dropdownData[fieldId].forEach(value => {
|
dropdownData[fieldId].forEach(value => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = value.IdCustomFieldsValue;
|
option.value = value.IdCustomFieldsValue;
|
||||||
option.textContent = value.Valore;
|
option.textContent = value.Valore;
|
||||||
if (dropdown.value === option.value) option.selected = true;
|
// Usa il valore corrente se disponibile, altrimenti usa data-selected-value
|
||||||
|
if (currentValue && currentValue === String(value.IdCustomFieldsValue)) {
|
||||||
|
option.selected = true;
|
||||||
|
} else if (!currentValue && selectedValue === String(value.IdCustomFieldsValue)) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
dropdown.appendChild(option);
|
dropdown.appendChild(option);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ((currentValue || selectedValue) && dropdown.value !== (currentValue || selectedValue)) {
|
||||||
|
dropdown.value = '';
|
||||||
|
console.warn(`Valore ${currentValue || selectedValue} non trovato per fieldId ${fieldId}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Esegui al caricamento della pagina
|
// Chiama populateDropdowns solo al caricamento iniziale
|
||||||
populateDropdowns();
|
populateDropdowns();
|
||||||
|
|
||||||
// Rielabora i dropdown quando si aggiunge una nuova riga (se applicabile)
|
|
||||||
document.querySelectorAll('.save-btn').forEach(btn => {
|
document.querySelectorAll('.save-btn').forEach(btn => {
|
||||||
btn.addEventListener('click', function() {
|
btn.addEventListener('click', function() {
|
||||||
setTimeout(populateDropdowns, 100); // Ritardo per garantire che il DOM sia aggiornato
|
const rowIndex = this.getAttribute('data-row');
|
||||||
|
const row = this.closest('.grid-row');
|
||||||
|
const iddatadb = row.getAttribute('data-id');
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
const inputs = row.querySelectorAll(`input[name^="rows[${rowIndex}]"], select[name^="rows[${rowIndex}]"]`);
|
||||||
|
inputs.forEach(input => {
|
||||||
|
const name = input.name.replace(`rows[${rowIndex}]`, '').replace(/\[|\]/g, '');
|
||||||
|
formData.append(name, input.value);
|
||||||
|
// Aggiorna data-selected-value per i dropdown
|
||||||
|
if (input.tagName === 'SELECT' && input.classList.contains('dropdown-select')) {
|
||||||
|
input.setAttribute('data-selected-value', input.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
formData.append('iddatadb', iddatadb);
|
||||||
|
formData.append('mapping', JSON.stringify(<?= json_encode($allMappings) ?>));
|
||||||
|
|
||||||
|
fetch('save_edited_row.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
const cells = row.querySelectorAll('.grid-cell');
|
||||||
|
cells.forEach(cell => {
|
||||||
|
cell.classList.remove('flash-success');
|
||||||
|
void cell.offsetWidth;
|
||||||
|
cell.classList.add('flash-success');
|
||||||
|
});
|
||||||
|
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
|
||||||
|
alert('Salvataggio avvenuto con successo!');
|
||||||
|
} else {
|
||||||
|
alert('Errore durante il salvataggio: ' + data.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => alert('Errore durante il salvataggio: ' + error.message));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gestione della propagazione per mantenere i valori sincronizzati
|
|
||||||
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
||||||
propagateButtons.forEach(button => {
|
propagateButtons.forEach(button => {
|
||||||
button.addEventListener('click', function() {
|
button.addEventListener('click', function() {
|
||||||
const columnIndex = this.getAttribute('data-column').replace('manual_', '');
|
const column = this.getAttribute('data-column');
|
||||||
const input = this.previousElementSibling;
|
const input = this.previousElementSibling;
|
||||||
const value = input.value;
|
const value = input.value;
|
||||||
|
|
||||||
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
||||||
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
||||||
cell.querySelector('.propagate-btn') === button
|
cell.querySelector('.propagate-btn[data-column="' + column + '"]')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (targetTopIndex !== -1) {
|
if (targetTopIndex !== -1) {
|
||||||
@@ -832,12 +1031,14 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
const cells = row.querySelectorAll('.grid-cell');
|
const cells = row.querySelectorAll('.grid-cell');
|
||||||
if (cells.length > targetTopIndex) {
|
if (cells.length > targetTopIndex) {
|
||||||
const targetInput = cells[targetTopIndex].querySelector('select.dropdown-select');
|
const targetInput = cells[targetTopIndex].querySelector('select.dropdown-select, input');
|
||||||
if (targetInput) {
|
if (targetInput) {
|
||||||
targetInput.value = value;
|
targetInput.value = value;
|
||||||
// Aggiorna visivamente il dropdown
|
if (targetInput.tagName === 'SELECT') {
|
||||||
const event = new Event('change');
|
targetInput.setAttribute('data-selected-value', value); // Aggiorna anche qui
|
||||||
targetInput.dispatchEvent(event);
|
const event = new Event('change');
|
||||||
|
targetInput.dispatchEvent(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -846,134 +1047,6 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<!-- dropdown with overlay -->
|
|
||||||
<!--
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
// Crea un overlay di caricamento
|
|
||||||
const loadingOverlay = document.createElement('div');
|
|
||||||
loadingOverlay.id = 'loading-overlay';
|
|
||||||
loadingOverlay.style.cssText = `
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.7);
|
|
||||||
z-index: 9999;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
const loadingMessage = document.createElement('div');
|
|
||||||
loadingMessage.style.cssText = `
|
|
||||||
color: white;
|
|
||||||
font-size: 24px;
|
|
||||||
padding: 20px;
|
|
||||||
background: #333;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
|
||||||
`;
|
|
||||||
loadingMessage.textContent = 'Loading Dropdown Options...';
|
|
||||||
loadingOverlay.appendChild(loadingMessage);
|
|
||||||
document.body.appendChild(loadingOverlay);
|
|
||||||
|
|
||||||
// Funzione originale populateDropdowns
|
|
||||||
async function populateDropdowns() {
|
|
||||||
const dropdowns = document.querySelectorAll('.dropdown-select');
|
|
||||||
if (dropdowns.length === 0) return;
|
|
||||||
|
|
||||||
const dropdownData = {};
|
|
||||||
|
|
||||||
// Recupera i dati solo per i field_id univoci
|
|
||||||
const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId);
|
|
||||||
for (const fieldId of uniqueFieldIds) {
|
|
||||||
if (!dropdownData[fieldId]) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`get_customfield_values.php?field_id=${fieldId}`);
|
|
||||||
const data = await response.json();
|
|
||||||
if (data.error) {
|
|
||||||
console.error('Errore per field_id', fieldId, ':', data.error);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dropdownData[fieldId] = data.CustomFieldsValues || [];
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Errore nel fetch per field_id', fieldId, ':', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Popola tutti i dropdown con i dati recuperati
|
|
||||||
dropdowns.forEach(dropdown => {
|
|
||||||
const fieldId = dropdown.getAttribute('data-field-id');
|
|
||||||
if (!fieldId || !dropdownData[fieldId]) {
|
|
||||||
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dropdown.innerHTML = '<option value="">Seleziona...</option>';
|
|
||||||
dropdownData[fieldId].forEach(value => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = value.IdCustomFieldsValue;
|
|
||||||
option.textContent = value.Valore;
|
|
||||||
if (dropdown.value === option.value) option.selected = true;
|
|
||||||
dropdown.appendChild(option);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Esegui al caricamento della pagina con l'overlay
|
|
||||||
async function loadDropdownsWithOverlay() {
|
|
||||||
console.log('Inizio caricamento tendine');
|
|
||||||
loadingOverlay.style.display = 'flex';
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 500)); // Minimo 500ms di visibilità
|
|
||||||
await populateDropdowns();
|
|
||||||
console.log('Caricamento tendine completato');
|
|
||||||
loadingOverlay.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Esegui il caricamento iniziale
|
|
||||||
loadDropdownsWithOverlay();
|
|
||||||
|
|
||||||
// Rielabora i dropdown quando si aggiunge una nuova riga
|
|
||||||
document.querySelectorAll('.save-btn').forEach(btn => {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
setTimeout(loadDropdownsWithOverlay, 100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Gestione della propagazione
|
|
||||||
const propagateButtons = document.querySelectorAll('.propagate-btn');
|
|
||||||
propagateButtons.forEach(button => {
|
|
||||||
button.addEventListener('click', function() {
|
|
||||||
const columnIndex = this.getAttribute('data-column').replace('manual_', '');
|
|
||||||
const input = this.previousElementSibling;
|
|
||||||
const value = input.value;
|
|
||||||
|
|
||||||
const gridTopCells = document.querySelector('.grid-top').querySelectorAll('.grid-cell');
|
|
||||||
const targetTopIndex = Array.from(gridTopCells).findIndex(cell =>
|
|
||||||
cell.querySelector('.propagate-btn') === button
|
|
||||||
);
|
|
||||||
|
|
||||||
if (targetTopIndex !== -1) {
|
|
||||||
const rows = document.querySelectorAll('.grid-row');
|
|
||||||
rows.forEach(row => {
|
|
||||||
const cells = row.querySelectorAll('.grid-cell');
|
|
||||||
if (cells.length > targetTopIndex) {
|
|
||||||
const targetInput = cells[targetTopIndex].querySelector('select.dropdown-select');
|
|
||||||
if (targetInput) {
|
|
||||||
targetInput.value = value;
|
|
||||||
const event = new Event('change');
|
|
||||||
targetInput.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
-->
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/import_debug.log');
|
||||||
|
if (!file_exists(__DIR__ . '/import_debug.log')) {
|
||||||
|
file_put_contents(__DIR__ . '/import_debug.log', "Inizio importazione alle " . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log iniziale
|
||||||
|
error_log("Inizio importazione alle " . date('Y-m-d H:i:s'));
|
||||||
|
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
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"));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$template_id = intval($_POST['template_id']);
|
||||||
|
$selected_rows = $_POST['selected_rows'];
|
||||||
|
$columns = json_decode($_POST['columns'], true); // Header dell'XLS
|
||||||
|
$rows = json_decode($_POST['rows'], true); // Dati dell'XLS
|
||||||
|
$newFilename = htmlspecialchars($_POST['filename']);
|
||||||
|
|
||||||
|
$_SESSION['template_id'] = $template_id;
|
||||||
|
$_SESSION['selected_rows'] = $selected_rows;
|
||||||
|
$_SESSION['columns'] = $columns;
|
||||||
|
$_SESSION['rows'] = $rows;
|
||||||
|
$_SESSION['filename'] = $newFilename;
|
||||||
|
|
||||||
|
error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows));
|
||||||
|
error_log("Columns: " . json_encode($columns));
|
||||||
|
error_log("Rows: " . json_encode($rows));
|
||||||
|
|
||||||
|
$user_id = $iduserlogin ?? 1; // Default a 1 se non definito
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// Genera un UUID univoco per importreferencecode
|
||||||
|
$importReferenceCode = date('YmdHis') . '-' . uniqid();
|
||||||
|
|
||||||
|
// Recupera tutti i mapping dal template
|
||||||
|
$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field FROM template_mapping WHERE template_id = ?");
|
||||||
|
$stmt->execute([$template_id]);
|
||||||
|
$allMappings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($allMappings)) {
|
||||||
|
header("Location: import_xls.php?id=$template_id&status=error&message=" . urlencode("Nessun mapping trovato per il template"));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trova il campo main_field
|
||||||
|
$mainFieldMapping = null;
|
||||||
|
foreach ($allMappings as $mapping) {
|
||||||
|
if ($mapping['main_field'] == 1) {
|
||||||
|
$mainFieldMapping = $mapping;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserisci le righe selezionate in datadb (solo campi generici con templateid)
|
||||||
|
$insertedIds = [];
|
||||||
|
foreach ($selected_rows as $rowIndex) {
|
||||||
|
$row = $rows[$rowIndex];
|
||||||
|
$values = [
|
||||||
|
$template_id, // templateid
|
||||||
|
$importReferenceCode, // importreferencecode
|
||||||
|
$newFilename, // filename_import
|
||||||
|
'i', // status
|
||||||
|
$user_id, // user_id
|
||||||
|
null, // limscode
|
||||||
|
date('Y-m-d') // importdate
|
||||||
|
];
|
||||||
|
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($values);
|
||||||
|
|
||||||
|
$iddatadb = $pdo->lastInsertId();
|
||||||
|
$insertedIds[] = $iddatadb;
|
||||||
|
|
||||||
|
// Inserisci tutti i campi (automatici e manuali) in import_data_details
|
||||||
|
foreach ($allMappings as $mapping) {
|
||||||
|
$fieldValue = null;
|
||||||
|
if (!$mapping['is_manual']) { // Campi automatici dall'XLS
|
||||||
|
$excelColumn = trim($mapping['excel_column']);
|
||||||
|
$excelColumnIndex = array_search($excelColumn, array_map('trim', $columns));
|
||||||
|
if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') {
|
||||||
|
$fieldValue = $row[$excelColumnIndex];
|
||||||
|
error_log("Found Excel column '$excelColumn' at index $excelColumnIndex, value: " . var_export($fieldValue, true));
|
||||||
|
} else {
|
||||||
|
$fieldValue = $mapping['manual_default'] ?? '';
|
||||||
|
error_log("Excel column '$excelColumn' not found or empty, using default: " . var_export($fieldValue, true));
|
||||||
|
}
|
||||||
|
switch ($mapping['data_type']) {
|
||||||
|
case 'INT':
|
||||||
|
$fieldValue = is_numeric($fieldValue) ? (int)$fieldValue : ($mapping['manual_default'] ?? 0);
|
||||||
|
break;
|
||||||
|
case 'DATE':
|
||||||
|
$fieldValue = !empty($fieldValue) ? date('Y-m-d', strtotime($fieldValue)) : ($mapping['manual_default'] === 'today' ? date('Y-m-d') : ($mapping['manual_default'] ?? ''));
|
||||||
|
break;
|
||||||
|
case 'CHAR':
|
||||||
|
$fieldValue = !empty($fieldValue) ? substr((string)$fieldValue, 0, 1) : ($mapping['manual_default'] ?? '');
|
||||||
|
break;
|
||||||
|
case 'Testo':
|
||||||
|
case 'VARCHAR':
|
||||||
|
default:
|
||||||
|
$fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { // Campi manuali
|
||||||
|
$fieldValue = $mapping['manual_default'] ?? '';
|
||||||
|
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
|
||||||
|
$fieldValue = date('Y-m-d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) {
|
||||||
|
error_log("Required field missing for mapping ID: " . $mapping['id'] . ", field: " . $mapping['field_label']);
|
||||||
|
}
|
||||||
|
error_log("Inserting into import_data_details - Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true) . ", Is Manual: " . $mapping['is_manual'] . ", Excel Column: " . ($mapping['excel_column'] ?? 'N/A') . ", Manual Default: " . ($mapping['manual_default'] ?? 'N/A'));
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$iddatadb, $mapping['id'], $fieldValue]);
|
||||||
|
error_log("Inserted into import_data_details for ID $iddatadb, Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['inserted_ids'] = $insertedIds;
|
||||||
|
|
||||||
|
$params = [
|
||||||
|
'template_id' => $template_id,
|
||||||
|
'filename' => $newFilename,
|
||||||
|
];
|
||||||
|
|
||||||
|
?>
|
||||||
|
<form id="redirectForm" action="import_edit2.php" method="post">
|
||||||
|
<input type="hidden" name="template_id" value="<?= htmlspecialchars($template_id) ?>">
|
||||||
|
<input type="hidden" name="filename" value="<?= htmlspecialchars($newFilename) ?>">
|
||||||
|
|
||||||
|
<?php foreach ($selected_rows as $row): ?>
|
||||||
|
<input type="hidden" name="selected_rows[]" value="<?= htmlspecialchars($row) ?>">
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php foreach ($insertedIds as $id): ?>
|
||||||
|
<input type="hidden" name="inserted_ids[]" value="<?= htmlspecialchars($id) ?>">
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<input type="hidden" name="columns" value='<?= json_encode($columns) ?>'>
|
||||||
|
<input type="hidden" name="rows" value='<?= json_encode($rows) ?>'>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
document.getElementById('redirectForm').submit();
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
exit;
|
||||||
|
|
||||||
@@ -126,7 +126,11 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<?php include('top_stat_widget.php'); ?>
|
<?php include('top_stat_widget.php'); ?>
|
||||||
|
<div class="mb-3 text">
|
||||||
|
<a href="historical_trf.php?id=<?= $id ?>&status=i" class="btn btn-warning me-2">Imported (i)</a>
|
||||||
|
<a href="historical_trf.php?id=<?= $id ?>&status=P" class="btn btn-primary me-2">In Progress (P)</a>
|
||||||
|
<a href="historical_trf.php?id=<?= $id ?>&status=l" class="btn btn-success">To LIMS (l)</a>
|
||||||
|
</div>
|
||||||
<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">
|
||||||
@@ -136,6 +140,7 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<!-- Form per caricare il file -->
|
<!-- Form per caricare il file -->
|
||||||
<form id="uploadForm" enctype="multipart/form-data" class="mb-4">
|
<form id="uploadForm" enctype="multipart/form-data" class="mb-4">
|
||||||
@@ -164,12 +169,12 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
<!--end wrapper-->
|
<!--end wrapper-->
|
||||||
|
|
||||||
<!-- search modal -->
|
<!-- search modal -->
|
||||||
<?php //include('include/searchmodal.php');
|
<?php //include('include/searchmodal.php');
|
||||||
?>
|
?>
|
||||||
<!-- end search modal -->
|
<!-- end search modal -->
|
||||||
|
|
||||||
<!--start switcher-->
|
<!--start switcher-->
|
||||||
<?php //include('include/themeswitcher.php');
|
<?php //include('include/themeswitcher.php');
|
||||||
?>
|
?>
|
||||||
<!--end switcher-->
|
<!--end switcher-->
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
@@ -205,7 +210,7 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
errorContainer.style.display = 'block';
|
errorContainer.style.display = 'block';
|
||||||
} else {
|
} else {
|
||||||
let html = `
|
let html = `
|
||||||
<form id="selectRowsForm" action="import_edit2.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='${JSON.stringify(data.columns)}'>
|
||||||
<input type="hidden" name="rows" value='${JSON.stringify(data.rows)}'>
|
<input type="hidden" name="rows" value='${JSON.stringify(data.rows)}'>
|
||||||
@@ -326,4 +331,4 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<li> <a href="import_dashboard.php"><i class='bx bx-radio-circle'></i>XLS Import</a>
|
<li> <a href="import_dashboard.php"><i class='bx bx-radio-circle'></i>XLS Import</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
https://93.43.5.102/limsapi/api/odata/Cliente(34)?expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Cliente(55)?expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Cliente(4202)?expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Cliente(4202)?expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Cliente(4202)?%24expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Cliente(4202)?%24expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Rapporto(2523026)?%24expand=CampioniDatiRapporto%2CAnalisiDatiRapporto%2CCustomFieldsDatiRapporto
|
|
||||||
https://93.43.5.102/limsapi/api/odata/Cliente(4202)?%24expand=SchemiAbilitati
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
// Parametri dalla richiesta AJAX
|
||||||
|
$template_id = intval($_GET['template_id'] ?? 0);
|
||||||
|
$status = $_GET['status'] ?? 'i';
|
||||||
|
$offset = intval($_GET['offset'] ?? 0);
|
||||||
|
$limit = intval($_GET['limit'] ?? 20);
|
||||||
|
|
||||||
|
if (!$template_id || !in_array($status, ['i', 'P', 'l'])) {
|
||||||
|
error_log("Errore in load_more_rows.php: Parametri non validi - template_id: $template_id, status: $status");
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Parametri non validi']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connessione al database
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// Recupera i dati
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
SELECT d.*, CONCAT(u.first_name, ' ', u.last_name) AS user_name
|
||||||
|
FROM datadb d
|
||||||
|
LEFT JOIN auth_users u ON d.user_id = u.id
|
||||||
|
WHERE d.templateid = ? AND d.status = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
");
|
||||||
|
$stmt->execute([$template_id, $status, $limit, $offset]);
|
||||||
|
$importedData = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Recupera i dettagli manuali
|
||||||
|
$insertedIds = array_column($importedData, 'iddatadb');
|
||||||
|
$manualDetails = [];
|
||||||
|
if (!empty($insertedIds)) {
|
||||||
|
$placeholders = implode(',', array_fill(0, count($insertedIds), '?'));
|
||||||
|
$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
|
||||||
|
FROM import_data_details d
|
||||||
|
JOIN template_mapping m ON d.mapping_id = m.id
|
||||||
|
WHERE d.id IN ($placeholders)
|
||||||
|
");
|
||||||
|
$stmt->execute($insertedIds);
|
||||||
|
$manualDetails = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepara i dati per il JSON
|
||||||
|
$rows = [];
|
||||||
|
foreach ($importedData as $row) {
|
||||||
|
$rowData = [
|
||||||
|
'iddatadb' => $row['iddatadb'] ?? '',
|
||||||
|
'importreferencecode' => $row['importreferencecode'] ?? '',
|
||||||
|
'filename_import' => $row['filename_import'] ?? '',
|
||||||
|
'status' => $row['status'] ?? '',
|
||||||
|
'importdate' => $row['importdate'] ?? '',
|
||||||
|
'details' => array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb'])
|
||||||
|
];
|
||||||
|
$rows[] = $rowData;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("load_more_rows.php: Caricate " . count($rows) . " righe per template_id=$template_id, status=$status, offset=$offset");
|
||||||
|
echo json_encode(['success' => true, 'rows' => $rows]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Errore in load_more_rows.php: " . $e->getMessage());
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
@@ -14,13 +14,18 @@ if (!$iddatadb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT file_path FROM datadb_photos WHERE iddatadb = :iddatadb LIMIT 1");
|
// Adjust the query to select all photo paths for the given iddatadb
|
||||||
|
$stmt = $pdo->prepare("SELECT file_path FROM datadb_photos WHERE iddatadb = :iddatadb");
|
||||||
$stmt->execute([':iddatadb' => $iddatadb]);
|
$stmt->execute([':iddatadb' => $iddatadb]);
|
||||||
$photo = $stmt->fetch(PDO::FETCH_ASSOC);
|
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if ($photo && $photo['file_path']) {
|
if ($photos && count($photos) > 0) {
|
||||||
$fullPath = '../photostrf/' . $photo['file_path']; // Assumi che le foto siano nella cartella photostrf
|
// Prepare an array of full file paths
|
||||||
echo json_encode(['success' => true, 'file_path' => $fullPath]);
|
$photoPaths = array_map(function($photo) {
|
||||||
|
return '../photostrf/' . $photo['file_path']; // Assuming the photos are stored in the "photostrf" folder
|
||||||
|
}, $photos);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'photos' => $photoPaths]); // Return an array of photo paths
|
||||||
} else {
|
} else {
|
||||||
echo json_encode(['success' => false, 'message' => 'Nessuna foto trovata']);
|
echo json_encode(['success' => false, 'message' => 'Nessuna foto trovata']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,48 +320,83 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
|
|||||||
|
|
||||||
async function populateDropdowns() {
|
async function populateDropdowns() {
|
||||||
const dropdowns = document.querySelectorAll('.dropdown-select');
|
const dropdowns = document.querySelectorAll('.dropdown-select');
|
||||||
if (dropdowns.length === 0) return;
|
if (dropdowns.length === 0) {
|
||||||
|
console.warn('Nessun dropdown di tipo SceltaMultipla trovato.');
|
||||||
const dropdownData = {};
|
return;
|
||||||
|
|
||||||
// Recupera i dati solo per i field_id univoci
|
|
||||||
const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId);
|
|
||||||
for (const fieldId of uniqueFieldIds) {
|
|
||||||
if (!dropdownData[fieldId]) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`get_customfield_values.php?field_id=${fieldId}`);
|
|
||||||
const data = await response.json();
|
|
||||||
if (data.error) {
|
|
||||||
console.error('Errore per field_id', fieldId, ':', data.error);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dropdownData[fieldId] = data.CustomFieldsValues || [];
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Errore nel fetch per field_id', fieldId, ':', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Popola tutti i dropdown con i dati recuperati
|
console.log(`Trovati ${dropdowns.length} dropdown da popolare.`);
|
||||||
dropdowns.forEach(dropdown => {
|
|
||||||
const fieldId = dropdown.getAttribute('data-field-id');
|
|
||||||
const manualDefault = dropdown.getAttribute('data-manual-default') || '';
|
|
||||||
if (!fieldId || !dropdownData[fieldId]) {
|
|
||||||
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dropdown.innerHTML = '<option value="">Seleziona...</option>';
|
const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId);
|
||||||
dropdownData[fieldId].forEach(value => {
|
|
||||||
const option = document.createElement('option');
|
if (uniqueFieldIds.length === 0) {
|
||||||
option.value = value.IdCustomFieldsValue;
|
console.warn('Nessun field_id valido trovato per i dropdown.');
|
||||||
option.textContent = value.Valore;
|
dropdowns.forEach(dropdown => {
|
||||||
if (manualDefault === String(value.IdCustomFieldsValue)) {
|
dropdown.innerHTML = '<option value="">Nessun field_id valido</option>';
|
||||||
option.selected = true;
|
dropdown.disabled = true;
|
||||||
}
|
|
||||||
dropdown.appendChild(option);
|
|
||||||
});
|
});
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Field IDs univoci:', uniqueFieldIds);
|
||||||
|
|
||||||
|
// Mostra l'overlay di caricamento
|
||||||
|
const loadingOverlay = document.getElementById('loading-overlay');
|
||||||
|
loadingOverlay.style.display = 'flex';
|
||||||
|
|
||||||
|
let dropdownData = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Usa field_ids come previsto dal backend
|
||||||
|
const fieldIdsQuery = uniqueFieldIds.join(',');
|
||||||
|
console.log(`Recupero dati per field_ids: ${fieldIdsQuery}`);
|
||||||
|
const response = await fetch(`get_customfield_values.php?field_ids=${fieldIdsQuery}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Errore HTTP: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.error) {
|
||||||
|
throw new Error(`Errore API: ${data.error}`);
|
||||||
|
}
|
||||||
|
dropdownData = data; // data è un oggetto come { "146": [], "156": [...] }
|
||||||
|
console.log('Dati totali restituiti:', dropdownData);
|
||||||
|
|
||||||
|
// Popola i dropdown
|
||||||
|
dropdowns.forEach(dropdown => {
|
||||||
|
const fieldId = dropdown.getAttribute('data-field-id');
|
||||||
|
const manualDefault = dropdown.getAttribute('data-manual-default') || '';
|
||||||
|
console.log(`Popolamento dropdown per field_id: ${fieldId}, manual_default: ${manualDefault}`);
|
||||||
|
|
||||||
|
dropdown.innerHTML = '<option value="">Seleziona...</option>';
|
||||||
|
|
||||||
|
if (!fieldId || !dropdownData[fieldId] || dropdownData[fieldId].length === 0) {
|
||||||
|
console.warn(`Nessun dato disponibile per field_id ${fieldId}`);
|
||||||
|
dropdown.innerHTML = `<option value="">Nessun valore (field_id ${fieldId} vuoto)</option>`;
|
||||||
|
dropdown.disabled = true; // Disabilita per evitare selezioni inutili
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dropdownData[fieldId].forEach(value => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = value.IdCustomFieldsValue;
|
||||||
|
option.textContent = value.Valore;
|
||||||
|
if (manualDefault && String(value.IdCustomFieldsValue) === String(manualDefault)) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
dropdown.appendChild(option);
|
||||||
|
});
|
||||||
|
dropdown.disabled = false;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Errore generale nel caricamento dei dropdown:', error);
|
||||||
|
dropdowns.forEach(dropdown => {
|
||||||
|
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
|
||||||
|
dropdown.disabled = true;
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
console.log('Nascondo overlay di caricamento.');
|
||||||
|
loadingOverlay.style.display = 'none';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carica i dropdown con overlay
|
// Carica i dropdown con overlay
|
||||||
|
|||||||
@@ -13,29 +13,32 @@
|
|||||||
<ul id="partsList" class="list-group"></ul>
|
<ul id="partsList" class="list-group"></ul>
|
||||||
<table class="table table-striped table-sm mt-3" id="partsTable">
|
<table class="table table-striped table-sm mt-3" id="partsTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Num. Parte</th>
|
<th>Num. Parte</th>
|
||||||
<th>Descrizione Parte</th>
|
<th>Descrizione Parte</th>
|
||||||
<th>Azioni</th>
|
<th>Azioni</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="partsTableBody">
|
<tbody id="partsTableBody">
|
||||||
<tr data-part-id="new">
|
<tr data-part-id="new">
|
||||||
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
|
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
|
||||||
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione" style="width: 100%;"></td>
|
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione" style="width: 100%;"></td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
|
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
|
||||||
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
|
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
|
||||||
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
||||||
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
||||||
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6>Foto del Campione</h6>
|
<h6>Foto del Campione</h6>
|
||||||
|
<div id="photoSelectorContainer" style="display: none;">
|
||||||
|
<!-- Dropdown or buttons for photo selection will appear here -->
|
||||||
|
</div>
|
||||||
<div style="position: relative; width: 100%; min-height: 400px;">
|
<div style="position: relative; width: 100%; min-height: 400px;">
|
||||||
<img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
<img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
||||||
<canvas id="photoCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
<canvas id="photoCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
||||||
@@ -142,4 +145,24 @@
|
|||||||
padding: 0.1rem 0.3rem;
|
padding: 0.1rem 0.3rem;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
/* ნორმალური Save ღილაკი */
|
||||||
|
#savePhotoBtn {
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* დაუმახსოვრებელი ცვლილებები */
|
||||||
|
#savePhotoBtn.unsaved {
|
||||||
|
background-color: #dc3545 !important; /* წითელი */
|
||||||
|
border-color: #dc3545 !important;
|
||||||
|
color: white !important;
|
||||||
|
animation: pulse 1.2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ლამაზი პულსაცია */
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
|
||||||
|
70% { box-shadow: 0 0 10px 15px rgba(220, 53, 69, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
console.log("parts.js caricato correttamente");
|
console.log("parts.js caricato correttamente");
|
||||||
|
|
||||||
// Gestione del popup per le parti
|
// ===================
|
||||||
|
// GLOBAL STATE (NEW)
|
||||||
|
// ===================
|
||||||
|
let photoData = {
|
||||||
|
naturalWidth: 0,
|
||||||
|
naturalHeight: 0,
|
||||||
|
displayWidth: 0,
|
||||||
|
displayHeight: 0,
|
||||||
|
scale: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// markers keyed by photo src => [{ partNumber, x, y } using NATURAL coords]
|
||||||
|
let photoMarkers = {};
|
||||||
|
|
||||||
|
// selection & descriptions
|
||||||
|
let selectedPartNumber = null;
|
||||||
|
let descriptionPosition = {x: 10, y: 10}; // NATURAL coords
|
||||||
|
let hasDescriptions = false;
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// POPUP HANDLING
|
||||||
|
// ===================
|
||||||
const partsButtons = document.querySelectorAll(".parts-btn");
|
const partsButtons = document.querySelectorAll(".parts-btn");
|
||||||
const partsModal = document.getElementById("partsModal");
|
const partsModal = document.getElementById("partsModal");
|
||||||
const closeBtn = document.querySelector("#partsModal .close-btn");
|
const closeBtn = document.querySelector("#partsModal .close-btn");
|
||||||
@@ -12,14 +33,8 @@ $(document).ready(function () {
|
|||||||
console.log("Pulsante Parts cliccato");
|
console.log("Pulsante Parts cliccato");
|
||||||
const iddatadb = $(this).data("iddatadb");
|
const iddatadb = $(this).data("iddatadb");
|
||||||
const rowIndex = $(this).data("row");
|
const rowIndex = $(this).data("row");
|
||||||
const importRef = $("table tbody tr")
|
const importRef = $("table tbody tr").eq(rowIndex).find("td").eq(1).text();
|
||||||
.eq(rowIndex)
|
const description = $("table tbody tr").eq(rowIndex).find("td").eq(2).text() || "Sconosciuto";
|
||||||
.find("td")
|
|
||||||
.eq(1)
|
|
||||||
.text();
|
|
||||||
const description =
|
|
||||||
$("table tbody tr").eq(rowIndex).find("td").eq(2).text() ||
|
|
||||||
"Sconosciuto";
|
|
||||||
|
|
||||||
$("#trfHeader").text(`${iddatadb} - ${importRef} - ${description}`);
|
$("#trfHeader").text(`${iddatadb} - ${importRef} - ${description}`);
|
||||||
$("#partsModal").data("iddatadb", iddatadb);
|
$("#partsModal").data("iddatadb", iddatadb);
|
||||||
@@ -36,7 +51,6 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gestione della chiusura del modal Parts
|
|
||||||
if (closeBtn) {
|
if (closeBtn) {
|
||||||
closeBtn.addEventListener("click", function () {
|
closeBtn.addEventListener("click", function () {
|
||||||
partsModal.style.display = "none";
|
partsModal.style.display = "none";
|
||||||
@@ -55,41 +69,26 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// PHOTO LOADERS
|
||||||
|
// ===================
|
||||||
function loadPhoto(iddatadb) {
|
function loadPhoto(iddatadb) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "load_photo.php",
|
url: "load_photo.php",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
data: { iddatadb: iddatadb },
|
data: {iddatadb: iddatadb},
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.success && response.file_path) {
|
if (response.success) {
|
||||||
const img = $("#samplePhoto");
|
if (response.photos && response.photos.length > 1) {
|
||||||
img.attr("src", response.file_path);
|
showPhotoSelector(response.photos);
|
||||||
img.on("load", function () {
|
} else if (response.photos && response.photos.length === 1) {
|
||||||
const container = img.parent();
|
loadSinglePhoto(response.photos[0]);
|
||||||
const canvas = document.getElementById("photoCanvas");
|
} else {
|
||||||
const containerWidth = container.width();
|
$("#samplePhoto").attr("src", "");
|
||||||
const containerHeight = container.height();
|
alert("Nessuna foto trovata per questo TRF.");
|
||||||
const scaleX = containerWidth / img[0].naturalWidth;
|
}
|
||||||
const scaleY = containerHeight / img[0].naturalHeight;
|
|
||||||
const scale = Math.min(scaleX, scaleY);
|
|
||||||
canvas.width = img[0].naturalWidth * scale;
|
|
||||||
canvas.height = img[0].naturalHeight * scale;
|
|
||||||
canvas.style.width = `${containerWidth}px`;
|
|
||||||
canvas.style.height = `${containerHeight}px`;
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
ctx.drawImage(
|
|
||||||
img.get(0),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
canvas.width,
|
|
||||||
canvas.height,
|
|
||||||
);
|
|
||||||
updateMarkers();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
$("#samplePhoto").attr("src", "");
|
alert(response.message || "Errore nel caricamento della foto.");
|
||||||
alert("Nessuna foto trovata per questo TRF.");
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
@@ -98,10 +97,89 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showPhotoSelector(photos) {
|
||||||
|
const selectorContainer = $("#photoSelectorContainer");
|
||||||
|
selectorContainer.empty();
|
||||||
|
|
||||||
|
const selector = $('<select id="photoSelector"></select>');
|
||||||
|
photos.forEach((photo, index) => {
|
||||||
|
const option = $('<option></option>').val(photo).text(`Photo ${index + 1}`);
|
||||||
|
// display option with photo name if available
|
||||||
|
if (photo.includes("/")) {
|
||||||
|
const photoName = photo.split("/").pop();
|
||||||
|
option.text(`Photo ${index + 1} - ${photoName}`);
|
||||||
|
}
|
||||||
|
selector.append(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
selector.on("change", function () {
|
||||||
|
const selectedPhoto = $(this).val();
|
||||||
|
loadSinglePhoto(selectedPhoto);
|
||||||
|
});
|
||||||
|
|
||||||
|
selectorContainer.append(selector);
|
||||||
|
selectorContainer.show();
|
||||||
|
|
||||||
|
if (photos.length > 0) {
|
||||||
|
selector.val(photos[0]);
|
||||||
|
loadSinglePhoto(photos[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSinglePhoto(photoPath) {
|
||||||
|
const img = $("#samplePhoto");
|
||||||
|
img.off("load"); // avoid stacking multiple handlers
|
||||||
|
img.attr("src", photoPath);
|
||||||
|
|
||||||
|
img.on("load", function () {
|
||||||
|
const canvas = document.getElementById("photoCanvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// Real image size
|
||||||
|
const naturalWidth = img[0].naturalWidth;
|
||||||
|
const naturalHeight = img[0].naturalHeight;
|
||||||
|
|
||||||
|
// Compute scale to FIT inside its parent without distorting aspect ratio
|
||||||
|
const parent = $(canvas).parent();
|
||||||
|
const maxW = parent.width();
|
||||||
|
const maxH = parent.height();
|
||||||
|
const scale = Math.min(maxW / naturalWidth, maxH / naturalHeight);
|
||||||
|
|
||||||
|
// Display size on screen
|
||||||
|
const displayWidth = Math.max(1, Math.round(naturalWidth * scale));
|
||||||
|
const displayHeight = Math.max(1, Math.round(naturalHeight * scale));
|
||||||
|
|
||||||
|
// Save globally
|
||||||
|
photoData = {naturalWidth, naturalHeight, displayWidth, displayHeight, scale};
|
||||||
|
|
||||||
|
// Canvas in REAL size (so saving uses natural coords 1:1)
|
||||||
|
canvas.width = naturalWidth;
|
||||||
|
canvas.height = naturalHeight;
|
||||||
|
|
||||||
|
// Visual size on screen
|
||||||
|
canvas.style.width = `${displayWidth}px`;
|
||||||
|
canvas.style.height = `${displayHeight}px`;
|
||||||
|
|
||||||
|
// Also size/align the overlay containers to match the canvas
|
||||||
|
$("#markerContainer").css({width: `${displayWidth}px`, height: `${displayHeight}px`});
|
||||||
|
$("#descriptionList").css({maxWidth: `${Math.max(200, Math.round(displayWidth * 0.35))}px`});
|
||||||
|
|
||||||
|
// Draw fresh image at full resolution
|
||||||
|
ctx.clearRect(0, 0, naturalWidth, naturalHeight);
|
||||||
|
ctx.drawImage(img.get(0), 0, 0, naturalWidth, naturalHeight);
|
||||||
|
|
||||||
|
updateMarkers();
|
||||||
|
if (hasDescriptions) drawDescriptions(descriptionPosition.x, descriptionPosition.y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// PARTS TABLE
|
||||||
|
// ===================
|
||||||
function addNewRow(nextPartNumber, isMix = false) {
|
function addNewRow(nextPartNumber, isMix = false) {
|
||||||
const description = isMix ? "Mix" : "";
|
const description = isMix ? "Mix" : "";
|
||||||
const newRow = `
|
const newRow = `
|
||||||
<tr data-part-id="new">
|
<tr data-part-id="">
|
||||||
<td><input type="number" class="form-control form-control-sm part-number" value="${nextPartNumber || 1}" style="width: 80px;"></td>
|
<td><input type="number" class="form-control form-control-sm part-number" value="${nextPartNumber || 1}" style="width: 80px;"></td>
|
||||||
<td><input type="text" class="form-control form-control-sm part-description" value="${description}" placeholder="Inserisci descrizione" style="width: 100%;"></td>
|
<td><input type="text" class="form-control form-control-sm part-description" value="${description}" placeholder="Inserisci descrizione" style="width: 100%;"></td>
|
||||||
<td>
|
<td>
|
||||||
@@ -111,33 +189,25 @@ $(document).ready(function () {
|
|||||||
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
||||||
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>`;
|
||||||
`;
|
|
||||||
$("#partsTableBody").append(newRow);
|
$("#partsTableBody").append(newRow);
|
||||||
updateRowButtons();
|
updateRowButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRowButtons() {
|
function updateRowButtons() {
|
||||||
const rowCount = $("#partsTableBody tr").length;
|
const rowCount = $("#partsTableBody tr").length;
|
||||||
$("#partsTableBody tr").each(function (index) {
|
$("#partsTableBody tr").each(function () {
|
||||||
const $removeBtn = $(this).find(".remove-row");
|
const $removeBtn = $(this).find(".remove-row");
|
||||||
if (rowCount > 1) {
|
if (rowCount > 1) $removeBtn.show(); else $removeBtn.hide();
|
||||||
$removeBtn.show();
|
|
||||||
} else {
|
|
||||||
$removeBtn.hide();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on("click", ".add-row", function (e) {
|
$(document).on("click", ".add-row", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log("Pulsante Aggiungi riga cliccato");
|
|
||||||
const maxPartNumber = Math.max(
|
const maxPartNumber = Math.max(
|
||||||
...$("#partsTableBody tr")
|
...$("#partsTableBody tr").map(function () {
|
||||||
.map(function () {
|
return parseInt($(this).find(".part-number").val()) || 0;
|
||||||
return parseInt($(this).find(".part-number").val()) || 0;
|
}).get(),
|
||||||
})
|
|
||||||
.get(),
|
|
||||||
);
|
);
|
||||||
addNewRow(maxPartNumber + 1);
|
addNewRow(maxPartNumber + 1);
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
@@ -145,13 +215,10 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
$(document).on("click", ".add-mix-row", function (e) {
|
$(document).on("click", ".add-mix-row", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log("Pulsante Aggiungi Mix cliccato");
|
|
||||||
const maxPartNumber = Math.max(
|
const maxPartNumber = Math.max(
|
||||||
...$("#partsTableBody tr")
|
...$("#partsTableBody tr").map(function () {
|
||||||
.map(function () {
|
return parseInt($(this).find(".part-number").val()) || 0;
|
||||||
return parseInt($(this).find(".part-number").val()) || 0;
|
}).get(),
|
||||||
})
|
|
||||||
.get(),
|
|
||||||
);
|
);
|
||||||
addNewRow(maxPartNumber + 1, true);
|
addNewRow(maxPartNumber + 1, true);
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
@@ -159,26 +226,16 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
$(document).on("click", ".remove-row", function (e) {
|
$(document).on("click", ".remove-row", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log("Pulsante Rimuovi riga cliccato");
|
|
||||||
const $row = $(this).closest("tr");
|
const $row = $(this).closest("tr");
|
||||||
const partId = $row.data("part-id");
|
const partId = $row.data("part-id");
|
||||||
console.log("ID parte da eliminare:", partId);
|
|
||||||
|
|
||||||
if (partId !== "new" && partId !== undefined && partId !== null) {
|
if (partId !== "new" && partId !== undefined && partId !== null) {
|
||||||
console.log("Procedo con la cancellazione dal database");
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "delete_part.php",
|
url: "delete_part.php",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
data: JSON.stringify({ part_id: partId }),
|
data: JSON.stringify({part_id: partId}),
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
beforeSend: function () {
|
|
||||||
console.log(
|
|
||||||
"Invio richiesta AJAX a delete_part.php con part_id:",
|
|
||||||
partId,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
console.log("Risposta da delete_part.php:", response);
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
$row.remove();
|
$row.remove();
|
||||||
updateRowButtons();
|
updateRowButtons();
|
||||||
@@ -189,21 +246,10 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
console.log("Errore AJAX:", status, error);
|
alert("Errore nell'eliminazione: " + error + ". Stato: " + xhr.status + " - " + xhr.responseText);
|
||||||
alert(
|
|
||||||
"Errore nell'eliminazione: " +
|
|
||||||
error +
|
|
||||||
". Stato: " +
|
|
||||||
xhr.status +
|
|
||||||
" - " +
|
|
||||||
xhr.responseText,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
|
||||||
'Riga non salvata nel database (partId = "new" o non definito), rimuovo solo visivamente',
|
|
||||||
);
|
|
||||||
$row.remove();
|
$row.remove();
|
||||||
updateRowButtons();
|
updateRowButtons();
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
@@ -220,11 +266,8 @@ $(document).ready(function () {
|
|||||||
const iddatadb = $("#partsModal").data("iddatadb");
|
const iddatadb = $("#partsModal").data("iddatadb");
|
||||||
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
|
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
|
||||||
|
|
||||||
console.log("Evento blur su input:", {
|
// არსებული part-id row-დან (თუ უკვე არსებობს)
|
||||||
partNumber,
|
const partId = $row.data("part-id") || null;
|
||||||
partDescription,
|
|
||||||
isMix,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (partDescription && iddatadb) {
|
if (partDescription && iddatadb) {
|
||||||
$saveLoading.show();
|
$saveLoading.show();
|
||||||
@@ -237,6 +280,7 @@ $(document).ready(function () {
|
|||||||
iddatadb: iddatadb,
|
iddatadb: iddatadb,
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
|
id: partId, // გავგზავნე part-ის ID (თუ არის)
|
||||||
part_number: partNumber,
|
part_number: partNumber,
|
||||||
part_description: partDescription,
|
part_description: partDescription,
|
||||||
mix: isMix,
|
mix: isMix,
|
||||||
@@ -246,16 +290,14 @@ $(document).ready(function () {
|
|||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
if (response.part_id) {
|
|
||||||
$row.data("part-id", response.part_id);
|
|
||||||
console.log(
|
|
||||||
"Aggiornato partId della riga:",
|
|
||||||
response.part_id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$saveLoading.hide();
|
$saveLoading.hide();
|
||||||
$saveStatus.show();
|
$saveStatus.show();
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
|
// თუ ახალია, backend-მა მოგვცა ახალი ID
|
||||||
|
if (response.part_id) {
|
||||||
|
$row.attr("data-part-id", response.part_id);
|
||||||
|
$row.data("part-id", response.part_id);
|
||||||
|
}
|
||||||
setTimeout(() => $saveStatus.hide(), 2000);
|
setTimeout(() => $saveStatus.hide(), 2000);
|
||||||
} else {
|
} else {
|
||||||
alert("Errore nel salvataggio: " + response.message);
|
alert("Errore nel salvataggio: " + response.message);
|
||||||
@@ -274,7 +316,7 @@ $(document).ready(function () {
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
url: "load_parts.php",
|
url: "load_parts.php",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
data: { iddatadb: iddatadb },
|
data: {iddatadb: iddatadb},
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
$("#partsTableBody").empty();
|
$("#partsTableBody").empty();
|
||||||
@@ -291,8 +333,7 @@ $(document).ready(function () {
|
|||||||
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
||||||
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>`;
|
||||||
`;
|
|
||||||
$("#partsTableBody").append(newRow);
|
$("#partsTableBody").append(newRow);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -301,10 +342,7 @@ $(document).ready(function () {
|
|||||||
updateRowButtons();
|
updateRowButtons();
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
} else {
|
} else {
|
||||||
alert(
|
alert("Errore nel caricamento delle parti: " + response.message);
|
||||||
"Errore nel caricamento delle parti: " +
|
|
||||||
response.message,
|
|
||||||
);
|
|
||||||
addNewRow(1);
|
addNewRow(1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -320,11 +358,7 @@ $(document).ready(function () {
|
|||||||
$("#partsTableBody tr").each(function () {
|
$("#partsTableBody tr").each(function () {
|
||||||
const partNumber = $(this).find(".part-number").val();
|
const partNumber = $(this).find(".part-number").val();
|
||||||
const partDescription = $(this).find(".part-description").val();
|
const partDescription = $(this).find(".part-description").val();
|
||||||
if (
|
if (partNumber && partDescription && !partDescription.startsWith("Mix")) {
|
||||||
partNumber &&
|
|
||||||
partDescription &&
|
|
||||||
!partDescription.startsWith("Mix")
|
|
||||||
) {
|
|
||||||
const listItem = `
|
const listItem = `
|
||||||
<li class="list-group-item" data-part-number="${partNumber}">
|
<li class="list-group-item" data-part-number="${partNumber}">
|
||||||
${partNumber} - ${partDescription}
|
${partNumber} - ${partDescription}
|
||||||
@@ -337,15 +371,10 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
$(document).on("click", ".add-to-mix-btn", function () {
|
$(document).on("click", ".add-to-mix-btn", function () {
|
||||||
const $listItem = $(this).closest("li");
|
const $listItem = $(this).closest("li");
|
||||||
const partDescription = $listItem.text().split(" - ")[1].trim(); // Prende tutta la descrizione dopo il trattino
|
const partDescription = $listItem.text().split(" - ")[1].trim();
|
||||||
const $mixRow = $("#partsTableBody tr")
|
const $mixRow = $("#partsTableBody tr").filter(function () {
|
||||||
.filter(function () {
|
return $(this).find(".part-description").val().startsWith("Mix");
|
||||||
return $(this)
|
}).last();
|
||||||
.find(".part-description")
|
|
||||||
.val()
|
|
||||||
.startsWith("Mix");
|
|
||||||
})
|
|
||||||
.last();
|
|
||||||
|
|
||||||
if ($mixRow.length === 0) {
|
if ($mixRow.length === 0) {
|
||||||
alert("Crea prima una riga Mix usando il pulsante 'M'.");
|
alert("Crea prima una riga Mix usando il pulsante 'M'.");
|
||||||
@@ -360,167 +389,131 @@ $(document).ready(function () {
|
|||||||
} else if (!currentDescription.includes(partDescription)) {
|
} else if (!currentDescription.includes(partDescription)) {
|
||||||
currentDescription += ` + ${partDescription}`;
|
currentDescription += ` + ${partDescription}`;
|
||||||
} else {
|
} else {
|
||||||
return; // Parte già presente, non aggiungerla
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$descriptionInput.val(currentDescription);
|
$descriptionInput.val(currentDescription);
|
||||||
$descriptionInput.trigger("blur"); // Attiva il salvataggio
|
$descriptionInput.trigger("blur");
|
||||||
updatePartsList();
|
updatePartsList();
|
||||||
});
|
});
|
||||||
|
|
||||||
let selectedPartNumber = null;
|
|
||||||
let markers = [];
|
|
||||||
let descriptionPosition = { x: 10, y: 10 };
|
|
||||||
let hasDescriptions = false;
|
|
||||||
|
|
||||||
$("#partsList").on("click", "li", function (e) {
|
$("#partsList").on("click", "li", function (e) {
|
||||||
if ($(e.target).hasClass("add-to-mix-btn")) return;
|
if ($(e.target).hasClass("add-to-mix-btn")) return;
|
||||||
selectedPartNumber = $(this).data("part-number");
|
selectedPartNumber = $(this).data("part-number");
|
||||||
console.log("Part number selezionato:", selectedPartNumber);
|
|
||||||
$(this).addClass("active").siblings().removeClass("active");
|
$(this).addClass("active").siblings().removeClass("active");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// MARKERS & DESCRIPTIONS
|
||||||
|
// ===================
|
||||||
const canvas = document.getElementById("photoCanvas");
|
const canvas = document.getElementById("photoCanvas");
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
$("#markerContainer").on("click", function (e) {
|
$("#markerContainer").on("click", function (e) {
|
||||||
console.log("Click sul markerContainer rilevato");
|
if (selectedPartNumber === null) return;
|
||||||
if (selectedPartNumber !== null) {
|
|
||||||
const img = $("#samplePhoto");
|
|
||||||
const canvas = document.getElementById("photoCanvas");
|
|
||||||
const rect = canvas.getBoundingClientRect();
|
|
||||||
const container = img.parent();
|
|
||||||
const containerWidth = container.width();
|
|
||||||
const containerHeight = container.height();
|
|
||||||
const scaleX = containerWidth / img.get(0).naturalWidth;
|
|
||||||
const scaleY = containerHeight / img.get(0).naturalHeight;
|
|
||||||
const scale = Math.min(scaleX, scaleY);
|
|
||||||
const x = (e.clientX - rect.left) / scale;
|
|
||||||
const y = (e.clientY - rect.top) / scale;
|
|
||||||
|
|
||||||
console.log("Coordinate cliccate (x, y):", x, y);
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const clickX = e.clientX - rect.left;
|
||||||
|
const clickY = e.clientY - rect.top;
|
||||||
|
|
||||||
const existingMarker = markers.find(
|
const x = clickX / photoData.scale; // convert to NATURAL coords
|
||||||
(m) => m.partNumber == selectedPartNumber,
|
const y = clickY / photoData.scale;
|
||||||
);
|
|
||||||
if (existingMarker) {
|
const currentPhoto = $("#samplePhoto").attr("src");
|
||||||
existingMarker.x = x;
|
if (!photoMarkers[currentPhoto]) photoMarkers[currentPhoto] = [];
|
||||||
existingMarker.y = y;
|
|
||||||
} else {
|
const existingMarker = photoMarkers[currentPhoto].find(m => m.partNumber == selectedPartNumber);
|
||||||
markers.push({ partNumber: selectedPartNumber, x, y });
|
if (existingMarker) {
|
||||||
}
|
existingMarker.x = x;
|
||||||
console.log("Markers aggiornati:", markers);
|
existingMarker.y = y;
|
||||||
updateMarkers();
|
|
||||||
if (hasDescriptions) {
|
|
||||||
drawDescriptions(descriptionPosition.x, descriptionPosition.y);
|
|
||||||
}
|
|
||||||
selectedPartNumber = null;
|
|
||||||
$("#partsList li").removeClass("active");
|
|
||||||
} else {
|
} else {
|
||||||
console.log("Nessun part number selezionato");
|
photoMarkers[currentPhoto].push({partNumber: selectedPartNumber, x, y});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateMarkers();
|
||||||
|
if (hasDescriptions) drawDescriptions(descriptionPosition.x, descriptionPosition.y);
|
||||||
|
|
||||||
|
selectedPartNumber = null;
|
||||||
|
$("#partsList li").removeClass("active");
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateMarkers() {
|
function updateMarkers() {
|
||||||
const img = $("#samplePhoto");
|
|
||||||
const container = img.parent();
|
|
||||||
const containerWidth = container.width();
|
|
||||||
const containerHeight = container.height();
|
|
||||||
const scaleX = containerWidth / img.get(0).naturalWidth;
|
|
||||||
const scaleY = containerHeight / img.get(0).naturalHeight;
|
|
||||||
const scale = Math.min(scaleX, scaleY);
|
|
||||||
|
|
||||||
const markerContainer = $("#markerContainer");
|
const markerContainer = $("#markerContainer");
|
||||||
markerContainer.empty();
|
markerContainer.empty();
|
||||||
|
|
||||||
|
// keep overlay sized to canvas display
|
||||||
|
markerContainer.css({width: `${photoData.displayWidth}px`, height: `${photoData.displayHeight}px`});
|
||||||
|
|
||||||
|
const currentPhoto = $("#samplePhoto").attr("src");
|
||||||
|
const markers = photoMarkers[currentPhoto] || [];
|
||||||
|
|
||||||
markers.forEach((marker) => {
|
markers.forEach((marker) => {
|
||||||
const scaledX = marker.x * scale;
|
const scaledX = marker.x * photoData.scale;
|
||||||
const scaledY = marker.y * scale;
|
const scaledY = marker.y * photoData.scale;
|
||||||
console.log(
|
|
||||||
"Aggiungo marker:",
|
const $marker = $(`<div class="draggable-marker">${marker.partNumber}</div>`).css({
|
||||||
marker.partNumber,
|
|
||||||
"a posizione (scaledX, scaledY):",
|
|
||||||
scaledX,
|
|
||||||
scaledY,
|
|
||||||
);
|
|
||||||
const $marker = $(
|
|
||||||
`<div class="draggable-marker">${marker.partNumber}</div>`,
|
|
||||||
).css({
|
|
||||||
left: scaledX - 8 + "px",
|
left: scaledX - 8 + "px",
|
||||||
top: scaledY - 8 + "px",
|
top: scaledY - 8 + "px",
|
||||||
});
|
});
|
||||||
markerContainer.append($marker);
|
markerContainer.append($marker);
|
||||||
makeDraggable($marker, marker, scale);
|
makeDraggable($marker, marker);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeDraggable($element, item, scale) {
|
function makeDraggable($element, item) {
|
||||||
let isDragging = false;
|
let isDragging = false;
|
||||||
let currentX = parseFloat($element.css("left")) || 0;
|
let startLeft = 0;
|
||||||
let currentY = parseFloat($element.css("top")) || 0;
|
let startTop = 0;
|
||||||
let initialX, initialY;
|
let initialX = 0;
|
||||||
|
let initialY = 0;
|
||||||
|
|
||||||
$element.on("mousedown", function (e) {
|
$element.on("mousedown", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
initialX = e.clientX - currentX;
|
startLeft = parseFloat($element.css("left")) || 0;
|
||||||
initialY = e.clientY - currentY;
|
startTop = parseFloat($element.css("top")) || 0;
|
||||||
|
initialX = e.clientX - startLeft;
|
||||||
|
initialY = e.clientY - startTop;
|
||||||
$element.css("z-index", 1001);
|
$element.css("z-index", 1001);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("mousemove", function (e) {
|
$(document).on("mousemove.dragMarker", function (e) {
|
||||||
if (isDragging) {
|
if (!isDragging) return;
|
||||||
e.preventDefault();
|
let currentX = e.clientX - initialX;
|
||||||
currentX = e.clientX - initialX;
|
let currentY = e.clientY - initialY;
|
||||||
currentY = e.clientY - initialY;
|
|
||||||
const container = $("#photoCanvas").parent();
|
|
||||||
const containerWidth = container.width();
|
|
||||||
const containerHeight = container.height();
|
|
||||||
const maxX = containerWidth - $element.width();
|
|
||||||
const maxY = containerHeight - $element.height();
|
|
||||||
|
|
||||||
currentX = Math.max(0, Math.min(currentX, maxX));
|
const maxX = photoData.displayWidth - $element.width();
|
||||||
currentY = Math.max(0, Math.min(currentY, maxY));
|
const maxY = photoData.displayHeight - $element.height();
|
||||||
|
|
||||||
$element.css({
|
currentX = Math.max(0, Math.min(currentX, maxX));
|
||||||
left: currentX + "px",
|
currentY = Math.max(0, Math.min(currentY, maxY));
|
||||||
top: currentY + "px",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (item.partNumber) {
|
$element.css({left: currentX + "px", top: currentY + "px"});
|
||||||
item.x = (currentX + 8) / scale;
|
|
||||||
item.y = (currentY + 8) / scale;
|
if (item && item.partNumber) {
|
||||||
} else {
|
item.x = (currentX + 8) / photoData.scale;
|
||||||
descriptionPosition.x = (currentX + 5) / scale;
|
item.y = (currentY + 8) / photoData.scale;
|
||||||
descriptionPosition.y = (currentY + 5) / scale;
|
} else {
|
||||||
}
|
// draggable description panel
|
||||||
|
descriptionPosition.x = (currentX + 5) / photoData.scale;
|
||||||
|
descriptionPosition.y = (currentY + 5) / photoData.scale;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("mouseup", function () {
|
$(document).on("mouseup.dragMarker", function () {
|
||||||
|
if (!isDragging) return;
|
||||||
isDragging = false;
|
isDragging = false;
|
||||||
$element.css("z-index", 1000);
|
$element.css("z-index", 1000);
|
||||||
|
$(document).off("mousemove.dragMarker mouseup.dragMarker");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawDescriptions(x, y) {
|
function drawDescriptions(x, y) {
|
||||||
const img = $("#samplePhoto");
|
|
||||||
const container = img.parent();
|
|
||||||
const containerWidth = container.width();
|
|
||||||
const containerHeight = container.height();
|
|
||||||
const scaleX = containerWidth / img.get(0).naturalWidth;
|
|
||||||
const scaleY = containerHeight / img.get(0).naturalHeight;
|
|
||||||
const scale = Math.min(scaleX, scaleY);
|
|
||||||
|
|
||||||
const partsList = [];
|
const partsList = [];
|
||||||
$("#partsTableBody tr").each(function () {
|
$("#partsTableBody tr").each(function () {
|
||||||
const partNumber = $(this).find(".part-number").val();
|
const partNumber = $(this).find(".part-number").val();
|
||||||
const partDescription = $(this).find(".part-description").val();
|
const partDescription = $(this).find(".part-description").val();
|
||||||
if (
|
if (partNumber && partDescription && !partDescription.startsWith("Mix")) {
|
||||||
partNumber &&
|
|
||||||
partDescription &&
|
|
||||||
!partDescription.startsWith("Mix")
|
|
||||||
) {
|
|
||||||
partsList.push(`${partNumber} ${partDescription}`);
|
partsList.push(`${partNumber} ${partDescription}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -529,148 +522,223 @@ $(document).ready(function () {
|
|||||||
descriptionList.empty();
|
descriptionList.empty();
|
||||||
descriptionList.css({
|
descriptionList.css({
|
||||||
display: "block",
|
display: "block",
|
||||||
top: y * scale + "px",
|
top: y * photoData.scale + "px",
|
||||||
left: x * scale + "px",
|
left: x * photoData.scale + "px",
|
||||||
width: "200px",
|
|
||||||
});
|
|
||||||
partsList.forEach((part) => {
|
|
||||||
descriptionList.append(`<div>${part}</div>`);
|
|
||||||
});
|
});
|
||||||
|
partsList.forEach((part) => descriptionList.append(`<div>${part}</div>`));
|
||||||
|
|
||||||
updateMarkers();
|
updateMarkers();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearCanvasMarkers() {
|
function clearCanvasMarkers() {
|
||||||
markers = [];
|
const currentPhoto = $("#samplePhoto").attr("src");
|
||||||
|
photoMarkers[currentPhoto] = [];
|
||||||
hasDescriptions = false;
|
hasDescriptions = false;
|
||||||
$("#descriptionList").css("display", "none");
|
$("#descriptionList").css("display", "none");
|
||||||
$("#markerContainer").empty();
|
$("#markerContainer").empty();
|
||||||
const canvas = document.getElementById("photoCanvas");
|
|
||||||
const img = $("#samplePhoto");
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
const container = img.parent();
|
|
||||||
const containerWidth = container.width();
|
|
||||||
const containerHeight = container.height();
|
|
||||||
const scaleX = containerWidth / img.get(0).naturalWidth;
|
|
||||||
const scaleY = containerHeight / img.get(0).naturalHeight;
|
|
||||||
const scale = Math.min(scaleX, scaleY);
|
|
||||||
|
|
||||||
canvas.width = img.get(0).naturalWidth * scale;
|
const canvas = document.getElementById("photoCanvas");
|
||||||
canvas.height = img.get(0).naturalHeight * scale;
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// reset canvas to current image (keeps proportions)
|
||||||
|
canvas.width = photoData.naturalWidth;
|
||||||
|
canvas.height = photoData.naturalHeight;
|
||||||
|
canvas.style.width = `${photoData.displayWidth}px`;
|
||||||
|
canvas.style.height = `${photoData.displayHeight}px`;
|
||||||
|
|
||||||
|
const img = $("#samplePhoto");
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.drawImage(img.get(0), 0, 0, canvas.width, canvas.height);
|
if (img[0].naturalWidth) {
|
||||||
|
ctx.drawImage(img.get(0), 0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#addDescriptionsBtn").on("click", function () {
|
$("#addDescriptionsBtn").on("click", function () {
|
||||||
hasDescriptions = true;
|
hasDescriptions = true;
|
||||||
descriptionPosition = { x: 10, y: 10 };
|
descriptionPosition = {x: 10, y: 10};
|
||||||
drawDescriptions(descriptionPosition.x, descriptionPosition.y);
|
drawDescriptions(descriptionPosition.x, descriptionPosition.y);
|
||||||
makeDraggable(
|
makeDraggable($("#descriptionList"));
|
||||||
$("#descriptionList"),
|
|
||||||
descriptionPosition,
|
|
||||||
Math.min(
|
|
||||||
$("#photoCanvas").parent().width() /
|
|
||||||
$("#samplePhoto").get(0).naturalWidth,
|
|
||||||
$("#photoCanvas").parent().height() /
|
|
||||||
$("#samplePhoto").get(0).naturalHeight,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#removeAnnotationsBtn").on("click", function () {
|
$("#removeAnnotationsBtn").on("click", function () {
|
||||||
clearCanvasMarkers();
|
clearCanvasMarkers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let unsavedChanges = false;
|
||||||
|
|
||||||
|
// --- helper functions ---
|
||||||
|
function markUnsaved() {
|
||||||
|
if (!unsavedChanges) {
|
||||||
|
unsavedChanges = true;
|
||||||
|
$("#savePhotoBtn").addClass("unsaved").text("⚠️ Salva Modifiche");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearUnsaved() {
|
||||||
|
unsavedChanges = false;
|
||||||
|
$("#savePhotoBtn").removeClass("unsaved").text("Salva Foto con Nome");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- event listeners ---
|
||||||
|
// როცა ვცვლით input-ს ცხრილში
|
||||||
|
$(document).on("input change", "#partsTableBody input", markUnsaved);
|
||||||
|
|
||||||
|
// როცა ვამატებთ/ვშლით რიგს
|
||||||
|
$(document).on("click", ".add-row, .add-mix-row, .remove-row", markUnsaved);
|
||||||
|
|
||||||
|
// თუ გაქვს draggable marker ან description list
|
||||||
|
$(document).on("markerChanged descriptionChanged", markUnsaved);
|
||||||
|
|
||||||
|
// --- modal close protection ---
|
||||||
|
$('#partsModal').on('hide.bs.modal', function (e) {
|
||||||
|
if (unsavedChanges) {
|
||||||
|
if (!confirm("Hai modifiche non salvate. Vuoi davvero uscire?")) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- SAVE BUTTON ---
|
||||||
$("#savePhotoBtn").on("click", function () {
|
$("#savePhotoBtn").on("click", function () {
|
||||||
const canvas = document.getElementById("photoCanvas");
|
const canvas = document.getElementById("photoCanvas");
|
||||||
const img = $("#samplePhoto");
|
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
|
const img = $("#samplePhoto");
|
||||||
|
|
||||||
canvas.width = img.get(0).naturalWidth;
|
// Ensure canvas is real size
|
||||||
canvas.height = img.get(0).naturalHeight;
|
const naturalWidth = img.get(0).naturalWidth;
|
||||||
ctx.drawImage(img.get(0), 0, 0);
|
const naturalHeight = img.get(0).naturalHeight;
|
||||||
|
canvas.width = naturalWidth;
|
||||||
|
canvas.height = naturalHeight;
|
||||||
|
|
||||||
|
// Redraw base image
|
||||||
|
ctx.drawImage(img.get(0), 0, 0, naturalWidth, naturalHeight);
|
||||||
|
|
||||||
|
// Descriptions box
|
||||||
const partsList = [];
|
const partsList = [];
|
||||||
$("#partsTableBody tr").each(function () {
|
$("#partsTableBody tr").each(function () {
|
||||||
const partNumber = $(this).find(".part-number").val();
|
const partNumber = $(this).find(".part-number").val();
|
||||||
const partDescription = $(this).find(".part-description").val();
|
const partDescription = $(this).find(".part-description").val();
|
||||||
if (
|
if (partNumber && partDescription && !partDescription.startsWith("Mix")) {
|
||||||
partNumber &&
|
|
||||||
partDescription &&
|
|
||||||
!partDescription.startsWith("Mix")
|
|
||||||
) {
|
|
||||||
partsList.push(`${partNumber} ${partDescription}`);
|
partsList.push(`${partNumber} ${partDescription}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasDescriptions) {
|
if (hasDescriptions && partsList.length > 0) {
|
||||||
ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
|
const fontSize = Math.round(naturalWidth * 0.02);
|
||||||
ctx.fillRect(
|
ctx.font = fontSize + "px Arial";
|
||||||
descriptionPosition.x,
|
const textHeight = fontSize + 8;
|
||||||
descriptionPosition.y,
|
const boxWidth = Math.round(naturalWidth * 0.28);
|
||||||
200,
|
const boxHeight = partsList.length * textHeight + 25;
|
||||||
partsList.length * 12 + 10,
|
|
||||||
);
|
const x = descriptionPosition.x;
|
||||||
ctx.fillStyle = "#000000";
|
const y = descriptionPosition.y;
|
||||||
ctx.font = "10px Arial";
|
|
||||||
|
// ჩრდილი
|
||||||
|
ctx.save();
|
||||||
|
ctx.shadowColor = "rgba(0,0,0,0.3)";
|
||||||
|
ctx.shadowBlur = 8;
|
||||||
|
ctx.shadowOffsetX = 3;
|
||||||
|
ctx.shadowOffsetY = 3;
|
||||||
|
|
||||||
|
// ლამაზი ბექგრაუნდი
|
||||||
|
ctx.fillStyle = "rgba(255, 255, 255, 0.9)";
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.roundRect(x, y, boxWidth, boxHeight, 12);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
// ტექსტი
|
||||||
|
ctx.fillStyle = "#111111";
|
||||||
partsList.forEach((part, index) => {
|
partsList.forEach((part, index) => {
|
||||||
ctx.fillText(
|
const domWidth = $("#samplePhoto").width();
|
||||||
part,
|
const domHeight = $("#samplePhoto").height();
|
||||||
descriptionPosition.x + 5,
|
|
||||||
descriptionPosition.y + 12 + index * 12,
|
// NATURAL ზომა (ფაილის რეალური ზომა)
|
||||||
);
|
const naturalWidth = photoData.naturalWidth;
|
||||||
|
const naturalHeight = photoData.naturalHeight;
|
||||||
|
|
||||||
|
// მასშტაბები
|
||||||
|
const scaleX = naturalWidth / domWidth;
|
||||||
|
const scaleY = naturalHeight / domHeight;
|
||||||
|
|
||||||
|
// გადაყვანილი კოორდინატები
|
||||||
|
const x = descriptionPosition.x * scaleX;
|
||||||
|
const y = descriptionPosition.y * scaleY;
|
||||||
|
|
||||||
|
ctx.fillText(part, x + 15, y + 35 + index * textHeight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Markers
|
||||||
|
const currentPhoto = $("#samplePhoto").attr("src");
|
||||||
|
const markers = photoMarkers[currentPhoto] || [];
|
||||||
markers.forEach((marker) => {
|
markers.forEach((marker) => {
|
||||||
|
const x = marker.x; // already NATURAL coords
|
||||||
|
const y = marker.y;
|
||||||
|
const radius = Math.max(5, Math.round(naturalWidth * 0.025));
|
||||||
|
const fontSize = Math.max(8, Math.round(radius * 0.9));
|
||||||
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(marker.x, marker.y, 8, 0, 2 * Math.PI);
|
ctx.arc(x, y, radius, 0, 2 * Math.PI);
|
||||||
ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
|
ctx.fillStyle = "rgba(255,0,0,0.85)";
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.strokeStyle = "#ff0000";
|
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 3;
|
||||||
|
ctx.strokeStyle = "#ffffff";
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
ctx.fillStyle = "#ffffff";
|
ctx.fillStyle = "#ffffff";
|
||||||
ctx.font = "bold 8px Arial";
|
ctx.font = `bold ${fontSize}px Arial`;
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
ctx.fillText(marker.partNumber, marker.x, marker.y);
|
ctx.fillText(marker.partNumber || "", x, y);
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataURL = canvas.toDataURL("image/png");
|
const dataURL = canvas.toDataURL("image/png");
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
||||||
const defaultName = `photo_${$("#partsModal").data("iddatadb")}_${timestamp}.png`;
|
const iddatadb = $("#partsModal").data("iddatadb");
|
||||||
const newName = prompt(
|
const defaultName = `photo_${iddatadb}_${timestamp}.png`;
|
||||||
"Inserisci il nome del file (senza estensione):",
|
|
||||||
defaultName.split(".png")[0],
|
const newName = prompt("Inserisci il nome del file (senza estensione):", defaultName.split(".png")[0]);
|
||||||
);
|
|
||||||
if (newName) {
|
if (newName) {
|
||||||
const finalName = newName + "_" + timestamp + ".png";
|
const finalName = newName + "_" + timestamp + ".png";
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "save_annotated_photo.php",
|
url: "save_annotated_photo.php",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
data: { dataURL: dataURL, filename: finalName },
|
data: {
|
||||||
|
dataURL: dataURL,
|
||||||
|
filename: finalName,
|
||||||
|
iddatadb: iddatadb
|
||||||
|
},
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
alert(
|
alert("Foto salvata con successo: " + response.file_path);
|
||||||
"Foto salvata con successo: " + response.file_path,
|
$("#samplePhoto").attr("src", response.file_path);
|
||||||
);
|
loadPhoto(iddatadb);
|
||||||
|
clearCanvasMarkers();
|
||||||
|
|
||||||
|
clearUnsaved(); // ✅ reset unsaved status
|
||||||
} else {
|
} else {
|
||||||
alert("Errore nel salvataggio: " + response.message);
|
alert("Errore: " + response.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
alert("Errore nel salvataggio della foto: " + error);
|
alert("Errore Ajax: " + error);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// DEBUG HOVER LOGS
|
||||||
|
// ===================
|
||||||
$(document).on("mouseenter", "tr", function () {
|
$(document).on("mouseenter", "tr", function () {
|
||||||
console.log("Mouse entrato su riga");
|
// console.log("Mouse entrato su riga");
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("mouseleave", "tr", function () {
|
$(document).on("mouseleave", "tr", function () {
|
||||||
console.log("Mouse uscito da riga");
|
// console.log("Mouse uscito da riga");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const webcamVideo = document.getElementById("webcamVideo");
|
const webcamVideo = document.getElementById("webcamVideo");
|
||||||
const captureBtn = document.getElementById("captureBtn");
|
const captureBtn = document.getElementById("captureBtn");
|
||||||
const closeWebcamBtn = document.getElementById("closeWebcamBtn");
|
const closeWebcamBtn = document.getElementById("closeWebcamBtn");
|
||||||
|
const webcamSelect = document.getElementById("webcamSelect");
|
||||||
let stream = null;
|
let stream = null;
|
||||||
|
|
||||||
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||||
@@ -41,25 +42,116 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
!webcamArea ||
|
!webcamArea ||
|
||||||
!webcamVideo ||
|
!webcamVideo ||
|
||||||
!captureBtn ||
|
!captureBtn ||
|
||||||
!closeWebcamBtn
|
!closeWebcamBtn ||
|
||||||
|
!webcamSelect
|
||||||
) {
|
) {
|
||||||
console.error("Elementi webcam mancanti");
|
console.error("Elementi webcam mancanti", {
|
||||||
|
openWebcamBtn,
|
||||||
|
webcamArea,
|
||||||
|
webcamVideo,
|
||||||
|
captureBtn,
|
||||||
|
closeWebcamBtn,
|
||||||
|
webcamSelect,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apri la webcam
|
// Funzione per avviare la webcam con un deviceId specifico
|
||||||
openWebcamBtn.addEventListener("click", async () => {
|
async function startWebcam(deviceId = null) {
|
||||||
try {
|
try {
|
||||||
stream = await navigator.mediaDevices.getUserMedia({
|
// Ferma il flusso video esistente, se presente
|
||||||
video: true,
|
if (stream) {
|
||||||
});
|
stream.getTracks().forEach((track) => track.stop());
|
||||||
|
stream = null;
|
||||||
|
webcamVideo.srcObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configura i vincoli per getUserMedia
|
||||||
|
const constraints = {
|
||||||
|
video: deviceId ? { deviceId: { exact: deviceId } } : true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Avvia il flusso video
|
||||||
|
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
webcamVideo.srcObject = stream;
|
webcamVideo.srcObject = stream;
|
||||||
webcamArea.style.display = "block";
|
webcamArea.style.display = "block";
|
||||||
openWebcamBtn.style.display = "none";
|
openWebcamBtn.style.display = "none";
|
||||||
dropArea.style.display = "none";
|
dropArea.style.display = "none";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error("Errore nell'accesso alla webcam:", error);
|
||||||
alert("Errore nell'accesso alla webcam: " + error.message);
|
alert("Errore nell'accesso alla webcam: " + error.message);
|
||||||
|
webcamArea.style.display = "none";
|
||||||
|
openWebcamBtn.style.display = "block";
|
||||||
|
dropArea.style.display = "block";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Funzione per popolare il dropdown delle webcam
|
||||||
|
async function populateWebcamSelect() {
|
||||||
|
try {
|
||||||
|
// Richiedi i permessi per accedere ai dispositivi
|
||||||
|
await navigator.mediaDevices.getUserMedia({ video: true });
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
const videoDevices = devices.filter(
|
||||||
|
(device) => device.kind === "videoinput",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Svuota il dropdown
|
||||||
|
webcamSelect.innerHTML =
|
||||||
|
'<option value="">Select a webcam</option>';
|
||||||
|
|
||||||
|
// Popola il dropdown con le webcam disponibili
|
||||||
|
videoDevices.forEach((device) => {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = device.deviceId;
|
||||||
|
option.text =
|
||||||
|
device.label || `Webcam ${webcamSelect.options.length}`;
|
||||||
|
webcamSelect.appendChild(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mostra il dropdown solo se ci sono più webcam
|
||||||
|
webcamSelect.style.display =
|
||||||
|
videoDevices.length > 1 ? "block" : "none";
|
||||||
|
|
||||||
|
// Avvia la webcam predefinita se ce n'è almeno una
|
||||||
|
if (videoDevices.length > 0) {
|
||||||
|
await startWebcam(videoDevices[0].deviceId);
|
||||||
|
} else {
|
||||||
|
alert("Nessuna webcam rilevata.");
|
||||||
|
webcamArea.style.display = "none";
|
||||||
|
openWebcamBtn.style.display = "block";
|
||||||
|
dropArea.style.display = "block";
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Errore nel recupero dei dispositivi:", error);
|
||||||
|
alert("Errore nel recupero dei dispositivi: " + error.message);
|
||||||
|
webcamSelect.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apri la webcam e popola il dropdown
|
||||||
|
openWebcamBtn.addEventListener("click", async () => {
|
||||||
|
await populateWebcamSelect();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gestisci il cambio della webcam selezionata
|
||||||
|
webcamSelect.addEventListener("change", async (e) => {
|
||||||
|
const deviceId = e.target.value;
|
||||||
|
if (deviceId) {
|
||||||
|
await startWebcam(deviceId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Chiudi la webcam
|
||||||
|
closeWebcamBtn.addEventListener("click", () => {
|
||||||
|
if (stream) {
|
||||||
|
stream.getTracks().forEach((track) => track.stop());
|
||||||
|
stream = null;
|
||||||
|
webcamVideo.srcObject = null;
|
||||||
|
}
|
||||||
|
webcamArea.style.display = "none";
|
||||||
|
openWebcamBtn.style.display = "block";
|
||||||
|
dropArea.style.display = "block";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cattura la foto
|
// Cattura la foto
|
||||||
@@ -71,7 +163,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
.getContext("2d")
|
.getContext("2d")
|
||||||
.drawImage(webcamVideo, 0, 0, canvas.width, canvas.height);
|
.drawImage(webcamVideo, 0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
// Converti l'immagine in un file
|
|
||||||
canvas.toBlob(async (blob) => {
|
canvas.toBlob(async (blob) => {
|
||||||
const file = new File(
|
const file = new File(
|
||||||
[blob],
|
[blob],
|
||||||
@@ -84,24 +175,16 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
loader.style.display = "flex";
|
loader.style.display = "flex";
|
||||||
}
|
}
|
||||||
await handleFiles([file], iddatadb);
|
await handleFiles([file], iddatadb);
|
||||||
closeWebcam();
|
if (stream) {
|
||||||
}, "image/jpeg");
|
stream.getTracks().forEach((track) => track.stop());
|
||||||
});
|
stream = null;
|
||||||
|
webcamVideo.srcObject = null;
|
||||||
// Chiudi la webcam
|
}
|
||||||
closeWebcamBtn.addEventListener("click", () => {
|
|
||||||
closeWebcam();
|
|
||||||
});
|
|
||||||
|
|
||||||
function closeWebcam() {
|
|
||||||
if (stream) {
|
|
||||||
stream.getTracks().forEach((track) => track.stop());
|
|
||||||
webcamVideo.srcObject = null;
|
|
||||||
webcamArea.style.display = "none";
|
webcamArea.style.display = "none";
|
||||||
openWebcamBtn.style.display = "block";
|
openWebcamBtn.style.display = "block";
|
||||||
dropArea.style.display = "block";
|
dropArea.style.display = "block";
|
||||||
}
|
}, "image/jpeg");
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funzione per attaccare gli event listener al contenuto del popup
|
// Funzione per attaccare gli event listener al contenuto del popup
|
||||||
@@ -198,6 +281,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
});
|
});
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
console.log(
|
||||||
|
"Foto eliminata con successo, ricarico popup",
|
||||||
|
);
|
||||||
loadPopupContent(iddatadb);
|
loadPopupContent(iddatadb);
|
||||||
} else {
|
} else {
|
||||||
alert(
|
alert(
|
||||||
|
|||||||
@@ -11,6 +11,24 @@ use Endroid\QrCode\QrCode;
|
|||||||
use Endroid\QrCode\RoundBlockSizeMode;
|
use Endroid\QrCode\RoundBlockSizeMode;
|
||||||
use Endroid\QrCode\Writer\PngWriter;
|
use Endroid\QrCode\Writer\PngWriter;
|
||||||
|
|
||||||
|
// Carica le variabili d'ambiente
|
||||||
|
try {
|
||||||
|
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../');
|
||||||
|
$dotenv->load();
|
||||||
|
error_log("File .env caricato correttamente da " . __DIR__ . '/../../.env');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Errore nel caricamento del file .env: " . $e->getMessage());
|
||||||
|
echo json_encode(['error' => 'Errore nel caricamento del file di configurazione']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica che BASE_URL sia definito
|
||||||
|
if (!isset($_ENV['BASE_URL'])) {
|
||||||
|
error_log("Errore: la variabile BASE_URL non è definita nel file .env");
|
||||||
|
echo json_encode(['error' => 'Variabile BASE_URL non definita']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
@@ -43,9 +61,9 @@ $photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|||||||
// Definisci il percorso base per le foto
|
// Definisci il percorso base per le foto
|
||||||
$photoBasePath = '../photostrf/';
|
$photoBasePath = '../photostrf/';
|
||||||
|
|
||||||
// Genera l'URL per il QR code
|
// Usa la variabile d'ambiente BASE_URL
|
||||||
$baseUrl = "http://localhost/trf_certest/public/userarea/"; // Sostituisci con il tuo dominio
|
$baseUrl = rtrim($_ENV['BASE_URL'], '/'); // Rimuove eventuali slash finali
|
||||||
$uploadUrl = $baseUrl . "upload_photos_mobile.php?iddatadb=" . $iddatadb;
|
$uploadUrl = $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb;
|
||||||
|
|
||||||
// Genera il QR code con endroid/qr-code 6.0.6
|
// Genera il QR code con endroid/qr-code 6.0.6
|
||||||
$qrCodeDir = '../photostrf/qrcodes/';
|
$qrCodeDir = '../photostrf/qrcodes/';
|
||||||
@@ -98,16 +116,19 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
|
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
<!-- Area per la webcam -->
|
<!-- Area per la webcam -->
|
||||||
|
<!-- Area per la webcam -->
|
||||||
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
|
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
|
||||||
<p>Webcam Preview</p>
|
<p>Webcam Preview</p>
|
||||||
|
<select id="webcamSelect" style="margin-bottom: 10px; padding: 5px;">
|
||||||
|
<option value="">Select a webcam</option>
|
||||||
|
</select>
|
||||||
<video id="webcamVideo" autoplay playsinline style="max-width: 100%; max-height: 300px;"></video>
|
<video id="webcamVideo" autoplay playsinline style="max-width: 100%; max-height: 300px;"></video>
|
||||||
<div style="margin-top: 10px;">
|
<div style="margin-top: 10px;">
|
||||||
<button id="captureBtn" style="padding: 10px 20px; background: #28a745; color: white; border: none; cursor: pointer;">Capture Photo</button>
|
<button id="captureBtn" style="padding: 10px 20px; background: #28a745; color: white; border: none; cursor: pointer;">Capture Photo</button>
|
||||||
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
|
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button>
|
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button> <!-- Elenco delle foto -->
|
||||||
<!-- Elenco delle foto -->
|
|
||||||
<div id="photosList">
|
<div id="photosList">
|
||||||
<?php if (empty($photos)): ?>
|
<?php if (empty($photos)): ?>
|
||||||
<p>No Photos present.</p>
|
<p>No Photos present.</p>
|
||||||
@@ -159,7 +180,6 @@ $result->saveToFile($qrCodeFile);
|
|||||||
background-color: #e9ecef;
|
background-color: #e9ecef;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stile per il modale dell'immagine ingrandita */
|
|
||||||
.image-modal {
|
.image-modal {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -199,7 +219,6 @@ $result->saveToFile($qrCodeFile);
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stili per il loader */
|
|
||||||
.loader {
|
.loader {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -1,25 +1,53 @@
|
|||||||
<?php
|
<?php
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
include('include/headscript.php');
|
include('include/headscript.php'); // აქედან უნდა იყოს DB კავშირიც
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
|
||||||
$dataURL = $_POST['dataURL'] ?? null;
|
$dataURL = $_POST['dataURL'] ?? null;
|
||||||
$filename = $_POST['filename'] ?? null;
|
$filename = $_POST['filename'] ?? null;
|
||||||
|
$iddatadb = $_POST['iddatadb'] ?? null; // 🟢 ახალი ველი
|
||||||
|
|
||||||
if (!$dataURL || !$filename) {
|
if (!$dataURL || !$filename || !$iddatadb) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// --- ფაილის შენახვა ---
|
||||||
$data = explode(',', $dataURL)[1];
|
$data = explode(',', $dataURL)[1];
|
||||||
$decodedData = base64_decode($data);
|
$decodedData = base64_decode($data);
|
||||||
$filePath = '../photostrf/annotated/' . $filename; // Crea una sottocartella 'annotated' per le foto modificate
|
|
||||||
if (!file_exists('../photostrf/annotated')) {
|
$dirPath = '../photostrf/annotated';
|
||||||
mkdir('../photostrf/annotated', 0777, true);
|
if (!file_exists($dirPath)) {
|
||||||
|
mkdir($dirPath, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$filePath = $dirPath . '/' . $filename;
|
||||||
file_put_contents($filePath, $decodedData);
|
file_put_contents($filePath, $decodedData);
|
||||||
echo json_encode(['success' => true, 'file_path' => $filePath, 'message' => 'Foto salvata con successo']);
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// --- ბაზაში ჩაწერა ---
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
INSERT INTO datadb_photos (iddatadb, file_path, file_name, uploaded_at, uploaded_by)
|
||||||
|
VALUES (:iddatadb, :file_path, :file_name, NOW(), :uploaded_by)
|
||||||
|
");
|
||||||
|
$stmt->execute([
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':file_path' => $filePath,
|
||||||
|
':file_name' => $filename,
|
||||||
|
':uploaded_by'=> $iduserlogin
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'file_path' => $filePath,
|
||||||
|
'message' => 'Foto salvata con successo e registrata nel DB'
|
||||||
|
]);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
echo json_encode(['success' => false, 'message' => 'Errore: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,28 +14,64 @@ try {
|
|||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Prepara i dati da aggiornare
|
$data = $_POST;
|
||||||
$updates = [];
|
$details = [];
|
||||||
$values = [];
|
|
||||||
foreach ($_POST as $key => $value) {
|
// 1. POST-დან ამოვიღოთ მხოლოდ details
|
||||||
if ($key !== 'iddatadb') {
|
foreach ($data as $key => $value) {
|
||||||
$updates[] = "$key = ?";
|
if (preg_match('/^details(\d+)field_value$/', $key, $matches)) {
|
||||||
$values[] = htmlspecialchars($value);
|
$id = $matches[1];
|
||||||
|
$details[$id] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$values[] = $iddatadb;
|
|
||||||
|
|
||||||
if (empty($updates)) {
|
// 2. DB-დან წამოვიღოთ არსებული მნიშვნელობები
|
||||||
throw new Exception('Nessun dato da aggiornare');
|
$stmt = $pdo->prepare("SELECT mapping_id, field_value FROM import_data_details WHERE id = ?");
|
||||||
|
$stmt->execute([$iddatadb]);
|
||||||
|
|
||||||
|
$currentValues = [];
|
||||||
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$currentValues[$row['mapping_id']] = $row['field_value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "UPDATE datadb SET " . implode(', ', $updates) . " WHERE iddatadb = ?";
|
// 3. შევადაროთ POST-ს და DB-ს
|
||||||
$stmt = $pdo->prepare($sql);
|
$changed = [];
|
||||||
$stmt->execute($values);
|
foreach ($details as $id => $newValue) {
|
||||||
|
$oldValue = $currentValues[$id] ?? null;
|
||||||
|
if ($oldValue !== $newValue) {
|
||||||
|
$changed[$id] = [
|
||||||
|
'old' => $oldValue,
|
||||||
|
'new' => $newValue
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. თუ არის ცვლილებები → UPDATE
|
||||||
|
if (!empty($changed)) {
|
||||||
|
$updateStmt = $pdo->prepare("
|
||||||
|
UPDATE import_data_details
|
||||||
|
SET field_value = :newValue
|
||||||
|
WHERE id = :iddatadb AND mapping_id = :mappingId
|
||||||
|
");
|
||||||
|
|
||||||
|
foreach ($changed as $mappingId => $values) {
|
||||||
|
$updateStmt->execute([
|
||||||
|
':newValue' => $values['new'],
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':mappingId' => $mappingId
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response['success'] = true;
|
||||||
|
$response['message'] = "Updated successfully";
|
||||||
|
$response['changed'] = $changed; // Debug / optional
|
||||||
|
} else {
|
||||||
|
$response['success'] = true;
|
||||||
|
$response['message'] = "No changes found";
|
||||||
|
}
|
||||||
|
|
||||||
$response['success'] = true;
|
|
||||||
$response['message'] = 'Riga aggiornata con successo';
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
$response['success'] = false;
|
||||||
$response['message'] = $e->getMessage();
|
$response['message'] = $e->getMessage();
|
||||||
error_log("Errore in save_edited_row.php: " . $e->getMessage());
|
error_log("Errore in save_edited_row.php: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
include('include/headscript.php');
|
include('include/headscript.php');
|
||||||
|
|
||||||
$dbHandler = DBHandlerSelect::getInstance();
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
@@ -17,20 +16,42 @@ if (!$iddatadb || empty($parts)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$part = $parts[0];
|
$part = $parts[0];
|
||||||
|
$partId = $part['id'] ?? null; // part_id თუ არსებობს
|
||||||
$partNumber = $part['part_number'] ?? null;
|
$partNumber = $part['part_number'] ?? null;
|
||||||
$partDescription = $part['part_description'] ?? '';
|
$partDescription = $part['part_description'] ?? '';
|
||||||
$mix = $part['mix'] ?? 'N'; // Aggiunto per gestire il campo mix
|
$mix = $part['mix'] ?? 'N';
|
||||||
|
|
||||||
if ($partDescription) {
|
if ($partDescription) {
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("INSERT INTO identification_parts (iddatadb, part_number, part_description, mix, created_at, updated_at) VALUES (:iddatadb, :part_number, :part_description, :mix, NOW(), NOW())");
|
if ($partId) {
|
||||||
$stmt->execute([
|
// UPDATE თუ უკვე არსებობს part
|
||||||
':iddatadb' => $iddatadb,
|
$stmt = $pdo->prepare("UPDATE identification_parts
|
||||||
':part_number' => $partNumber,
|
SET part_number = :part_number,
|
||||||
':part_description' => $partDescription,
|
part_description = :part_description,
|
||||||
':mix' => $mix
|
mix = :mix,
|
||||||
]);
|
updated_at = NOW()
|
||||||
echo json_encode(['success' => true, 'message' => 'Parte salvata con successo']);
|
WHERE id = :id");
|
||||||
|
$stmt->execute([
|
||||||
|
':id' => $partId,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix
|
||||||
|
]);
|
||||||
|
echo json_encode(['success' => true, 'part_id' => $partId, 'part_number'=>$partNumber, 'message' => 'Parte aggiornata con successo']);
|
||||||
|
} else {
|
||||||
|
// INSERT თუ ახალია
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO identification_parts
|
||||||
|
(iddatadb, part_number, part_description, mix, created_at, updated_at)
|
||||||
|
VALUES (:iddatadb, :part_number, :part_description, :mix, NOW(), NOW())");
|
||||||
|
$stmt->execute([
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix
|
||||||
|
]);
|
||||||
|
$newId = $pdo->lastInsertId();
|
||||||
|
echo json_encode(['success' => true, 'part_id' => $newId, 'part_number'=>$partNumber, 'message' => 'Parte salvata con successo']);
|
||||||
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,4 +142,4 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
|
|||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
<script src="{{ url(mix('assets/js/vendor.js')) }}"></script>
|
<script src="{{ url(mix('assets/js/vendor.js')) }}"></script>
|
||||||
<script src="{{ url('assets/js/as/app.js') }}"></script>
|
<script src="{{ url('assets/js/as/app.js') }}"></script>
|
||||||
|
<script src="{{ url('assets/js/alpinejs.js') }}"></script>
|
||||||
@yield('scripts')
|
@yield('scripts')
|
||||||
|
|
||||||
@hook('app:scripts')
|
@hook('app:scripts')
|
||||||
|
|||||||
@@ -188,3 +188,11 @@ Route::group(['prefix' => 'install'], function () {
|
|||||||
Route::get('complete', 'InstallController@complete')->name('install.complete');
|
Route::get('complete', 'InstallController@complete')->name('install.complete');
|
||||||
Route::get('error', 'InstallController@error')->name('install.error');
|
Route::get('error', 'InstallController@error')->name('install.error');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
use App\Vanguard\Http\Controllers\Userarea\UploadPhotosMobileController;
|
||||||
|
|
||||||
|
Route::get('/userarea/upload-photos-mobile', [UploadPhotosMobileController::class, 'index'])
|
||||||
|
->name('userarea.upload-photos-mobile.index');
|
||||||
|
|
||||||
|
Route::post('/userarea/upload-photos-mobile', [UploadPhotosMobileController::class, 'upload'])
|
||||||
|
->name('userarea.upload-photos-mobile.upload');
|
||||||
|
|||||||