Compare commits

...

134 Commits

Author SHA1 Message Date
RMubarakzyanov a626c8283e upload photos to main campione only 2026-02-28 15:48:19 +03:00
RMubarakzyanov c7416ba4a9 fix photo upload endpoint and align CommessaWeb field names with API docs
- CommessaWeb POST: rename fields per documentation — CustomerManager, PriceMultiplier, CertestObjectMasterData, CertestServiceMasterData, CustomerSupplier
- Move DeliveryRequest (ConsegnaRichiesta) from CommessaWeb to Campione
- Photo upload: change endpoint from AllegatoCommessaWeb to Campione({id})/UploadCampioneFile, upload to all campioni
- postMultipart(): remove commessaId param, send only file field
2026-02-28 02:07:40 +03:00
RMubarakzyanov 1fed113c5c VisualLimsApiClientMock: fake data for all LIMS endpoints; getInstance() branches on SIMULATE_EXPORT_LIMS
get_clienti.php, get_fixed_field_data.php: simulate mode support
CustomField dropdown values mock added (get_customfield_values.php)

exportUnsavedModal: prompt save before export, MutationObserver waits for save, then proceeds to confirm
Removed old jQuery .export-lims-btn handler that bypassed confirm modal
Fix false "Unsaved changes" on page load: data-restoring guard in all programmatic trigger/dispatchEvent calls (populateSelect, populateClientDropdowns, populateDropdowns)

Fix ConsegnaRichiesta not shown on refresh: add to PHP $fixedAliasMap
Add step5_2_photos, step9_1_importa
2026-02-28 00:44:21 +03:00
RMubarakzyanov e3994d6f9f fix notices running on php-8.2 2026-02-26 22:59:41 +03:00
solocla 9af0df3cca env example update 2026-02-26 17:14:16 +01:00
solocla 48d2a3ff42 time and date setting 2026-02-25 22:07:44 +01:00
solocla cf44e67922 added auto user accettatore id 2026-02-25 15:24:41 +01:00
solocla 35021e9d9b dropdown in alphabetical order 2026-02-25 10:02:45 +01:00
solocla 497ebda65a update gitignore 2026-02-24 09:09:32 +01:00
solocla b0024edb70 mapping fixed 2026-02-24 09:06:45 +01:00
solocla b9852ba226 saved rows 2026-02-19 12:07:32 +01:00
solocla 407d6884a1 fixed note save and import special character 2026-02-19 11:55:24 +01:00
solocla 1a4beadbb2 fixed propagate dropdown 2026-02-18 11:52:26 +01:00
solocla 4bb0445cff added select 2 on all fields (with limit of 12) 2026-02-18 10:48:04 +01:00
solocla 73dd8f4ce8 fixed column size final 2026-02-18 10:04:27 +01:00
solocla bdc4e0e60c fixed size column 2026-02-18 09:58:42 +01:00
solocla ef8f2d8000 fixed labels 2026-02-18 09:54:21 +01:00
solocla 74c9a1d02a added time field 2026-02-18 09:34:26 +01:00
solocla cd3bccd183 added multiple tested components 2026-02-17 09:04:30 +01:00
solocla 78154e43a9 fixed tested components 2026-02-05 10:32:28 +01:00
solocla 9fe9243e60 fixed mapping template 2026-02-05 09:05:51 +01:00
solocla a8330d4aba fixed layout 2026-02-04 15:31:53 +01:00
MGrigoryan 82d6a2ee18 feat(import_edit2): expand entire column including header and fix sticky columns 2026-02-04 17:00:01 +04:00
MGrigoryan d8eddb3aa5 feat(import_edit2): enhance grid UI with sticky columns and textarea conversion
- Fix grid-top alignment and datepicker positioning
- Extend column resizer to grid-top cells
- Add sticky columns for Actions and Sample Description
- Implement input-to-textarea conversion on focus
- Increase Select2 dropdown height
- Improve grid-container CSS for sticky support
2026-02-04 11:59:59 +04:00
solocla f60dc64b2d fixed importedit 2026-02-02 08:46:47 +01:00
solocla 4e4cae1df8 added fixed fields 2026-01-30 12:07:43 +01:00
solocla 8838edf3a1 fixed fields 2026-01-28 11:49:11 +01:00
solocla e75be99e43 added resort manually 2025-11-08 17:55:10 +01:00
solocla a482d975da Merge branch 'feature/parts-photo-load-from-quotation' 2025-10-31 10:38:28 +01:00
solocla 598a2cc84c change marker dimension 2025-10-31 10:16:57 +01:00
MGrigoryan 6ec0c2062e fix: Include single sample photo in save operation when no photos selected 2025-10-31 11:45:04 +04:00
MGrigoryan 5eb5bd1613 fix: deselect part when clicking selected row 2025-10-31 11:30:18 +04:00
MGrigoryan 03771e3ca8 feat: Add quotation modal and iddatadb update for quotation parts/images
- Add quotation modal for selecting quotation
- Load quotation parts and photos
- Update iddatadb with quotation parts and photo references
2025-10-31 11:26:11 +04:00
MGrigoryan 03642fdfab feat(annotations): support multiple pins per part 2025-10-30 17:08:57 +04:00
MGrigoryan f6ea17388c fix(partsTable, annotationsModal): correct table height and restore "Torna alle Parti"
- partsTable: reduce excessive height to prevent oversized rendering
- annotationsModal: fix "Torna alle Parti" button behavior to return to parts view
2025-10-30 10:26:46 +04:00
solocla 1c2b4ab7a6 Merge branch 'bugfix/part-creation-matrice-dropdown-fix' 2025-10-29 18:25:26 +01:00
MGrigoryan 31cb23b00e fix(partsTable): skip change handler when setting Select2 value programmatically
Pass skipHandler flag in change event data to prevent handler execution
during programmatic value updates.
2025-10-29 19:18:33 +04:00
MGrigoryan d29563d20d feat(partsTable): add image icon to show/hide photo button
- Add image icon alongside eye icon in show/hide photo button
- Improve visual indication of photo toggle functionality
2025-10-29 18:27:33 +04:00
solocla 82af925ac1 added size to line markers 2025-10-29 13:45:38 +01:00
solocla 5d8360dd87 marker with size 2025-10-29 12:32:09 +01:00
MGrigoryan 683073c244 fix(partsTable): initialize new item matrice as empty and refresh on global filter change
- Default new items' matrice to empty to prevent stale values leaking from prior state
- Force matrice update when the global filter changes to keep items in sync
2025-10-29 14:17:00 +04:00
solocla 8d6fe92481 fixed multiple parts mix and single line 2025-10-28 08:58:39 +01:00
solocla dbc66723a6 fixed color save 2025-10-27 15:53:12 +01:00
solocla 218fc14462 fixed country client and parts column matrice 2025-10-27 14:38:20 +01:00
solocla 29e4b41874 update export to lims 2025-10-11 20:19:43 +02:00
solocla eef9ae8d36 added note to export 2025-10-10 11:31:49 +02:00
solocla 68c867a3f4 change clienti to datadb and fixed column pages 2025-10-09 15:30:44 +02:00
solocla a9827e4e81 added note and date to identification parts 2025-10-08 17:34:21 +02:00
solocla b51936f784 various fixing modal 2025-10-07 20:56:57 +02:00
solocla 15b6f38e8b fixed matrici with db cron 2025-10-07 09:41:29 +02:00
solocla 12c6cc5f95 lazy load modal parts and matrici cron 2025-10-07 09:12:54 +02:00
solocla a0b12463c0 fixed for matrici 2025-10-03 08:52:37 +02:00
solocla 07ddcafd3f fixed nologin 2025-09-27 13:38:26 +02:00
solocla 7843d4b1fc added nologin 2025-09-27 13:37:37 +02:00
solocla 4eae855e23 added headscriptnologin 2025-09-27 13:36:26 +02:00
solocla c709f64a17 remove login smartphone 2025-09-27 13:33:23 +02:00
solocla d5f0690f59 background trasparent annotation 2025-09-27 13:28:21 +02:00
solocla 6bbd3fcae9 fixed get clienti with id, nominativo and country 2025-09-27 09:53:21 +02:00
solocla 9e19e9e1d4 fixed export to lims, fixed multiple upload, added calendar to Data 2025-09-27 09:44:00 +02:00
solocla 7caee9c994 prova 2025-09-26 11:27:33 +02:00
solocla f8320315f7 historical added commessaweb., edit added tested components 2025-09-26 09:28:49 +02:00
solocla 7397d86bc2 fixed template dashboard 2025-09-25 14:26:22 +02:00
solocla 2deb1f101a hide column and fixed edit template 2025-09-25 14:18:09 +02:00
solocla ed4467337f update moncler routine 2025-09-25 11:03:47 +02:00
solocla 864714d198 routine scripts 2025-09-24 14:18:31 +02:00
solocla 33aacfb469 env example 2025-09-23 17:39:44 +02:00
solocla e0e262fd32 Merge feature/lims-api into main, prefer lims-api version for conflicted files 2025-09-23 14:24:54 +02:00
solocla 5d6302fa9c added admin role to button export 2025-09-23 10:33:16 +02:00
solocla 3da8ff81c9 added record idcommessaweb and commessaweb and update status to export to lims 2025-09-23 09:44:58 +02:00
kapsona777 a36dd02771 Lims api working version without comment 2025-09-22 20:24:53 +04:00
kapsona777 0a6fb98476 Lims api working version with comments 2025-09-22 20:16:56 +04:00
solocla 57ddd4bb5a fixed photo quotations 2025-09-22 11:22:05 +02:00
solocla df5e6d5656 fixed save photos for modsecurity 2025-09-22 10:47:48 +02:00
solocla 78495880ca fixed quotations 2025-09-22 09:19:36 +02:00
solocla 960832efb1 Merge feature/quotations into main, prefer quotations version for modal_parts.php and parts.js 2025-09-22 08:24:05 +02:00
solocla 447a0d1dea fixed canvas dimension 2025-09-22 08:15:01 +02:00
solocla 5b47416841 fixed part.js 2025-09-22 07:59:13 +02:00
solocla 3e4a627ca7 fixed quotations 2025-09-20 22:00:16 +02:00
solocla 420b0a0405 added routine to insert templates 2025-09-19 12:15:41 +02:00
solocla b39d601ec9 Merge branch 'features/routine' 2025-09-19 12:10:01 +02:00
solocla 89d13699b4 added routine functionalites to template 2025-09-19 12:09:01 +02:00
solocla 9826331545 update 2025-09-19 11:45:21 +02:00
solocla 9d8718d110 only entraid provider 2025-09-19 09:50:57 +02:00
solocla 16e00f8573 entraid integration completa with docs 2025-09-19 09:31:20 +02:00
solocla baf3f6da32 photo size fixed 2025-09-18 17:02:38 +02:00
solocla 62bf4ebd92 export to lims 2025-09-18 12:00:43 +02:00
solocla 6e465e3010 fixed color parts 2025-09-17 09:41:51 +02:00
solocla 8b08969c69 get matrice 2025-09-16 11:39:44 +02:00
solocla 25d4519684 fixed quotations 2025-09-13 21:28:11 +02:00
solocla 34d4dc8660 quotations page 2025-09-13 12:31:31 +02:00
solocla 1510ef03f1 added level to collahge 2025-09-12 18:09:01 +02:00
solocla ce8c95921f remove .env from repository 2025-09-12 10:17:22 +02:00
solocla 095a6ae879 remove debug/log/json files from tracking 2025-09-12 10:03:50 +02:00
solocla 296143016a template mapping addes is visible as checkbox and is required as badge 2025-09-12 10:01:19 +02:00
kapsona777 412dce8941 refactored api code 2025-09-11 18:46:47 +04:00
kapsona777 586226ceaf fixed alert issue 2025-09-10 20:54:31 +04:00
kapsona777 ac09d8d0eb fixed issue, now works great. // ⚠️ Simulation ON (change it to false to enable real API calls)
$simulate = true;
2025-09-10 20:30:02 +04:00
kapsona777 33e3ae059d this commit is uploaded for testing only, no api calls are made 2025-09-09 17:28:48 +04:00
solocla 3aa2504f3c fixed cut 2025-09-08 14:01:17 +02:00
solocla c1a396f246 added canvas functionality 2025-09-08 11:40:43 +02:00
solocla a45ba1c8b3 added cut 2025-09-08 10:26:15 +02:00
solocla 7a944a73f7 get_commessaweb 2025-09-08 08:42:05 +02:00
solocla 71595cc8de added speech functions 2025-09-06 18:48:38 +02:00
solocla f89dbd0c23 added save all 2025-09-06 12:29:29 +02:00
solocla 9ba859e15b Merge remote-tracking branch 'origin/bugfix/warning-text-and-logic-change' 2025-09-05 21:44:38 +02:00
solocla 672e448e9a fixed renumerate parts 2025-09-04 15:16:19 +02:00
solocla 0749032fbc added collage, fixed parts marker color, added ri number 2025-09-04 15:01:03 +02:00
kapsona777 d692614f70 warning fix 2025-09-01 19:56:08 +04:00
solocla 1303cff9fd added export to lims button 2025-08-29 15:36:55 +02:00
solocla 6b2bd0964b fixed dropdown selection 2025-08-28 10:25:12 +02:00
solocla 0d2cf13524 update historical trf 2025-08-28 09:36:16 +02:00
solocla f6ef9c39d2 added multi webcam functionality 2025-08-27 20:21:38 +02:00
solocla 7e4ed56f28 Merge feature/historical_imported_trf into main (kept main version for logs and import_edit2.php) 2025-08-27 12:16:41 +02:00
solocla 4d0644f46c metada classes 2025-08-27 08:09:42 +02:00
solocla 712042b8d8 update layout table import edit 2 and fix address photos in env 2025-08-26 15:22:27 +02:00
solocla efee12740d fixed mappiung template 2025-08-26 11:54:03 +02:00
solocla 14395810d0 fixed template mapping 2025-08-26 11:49:08 +02:00
solocla 03002a8938 gitignore edit 2025-08-26 10:51:52 +02:00
solocla 21fcee8ff5 Merge feature/added-some-features into main (ignore debug log conflicts) 2025-08-26 10:46:27 +02:00
kapsona777 1361340928 fixed annotation description placement 2025-08-25 19:59:22 +04:00
kapsona777 1bda30e957 fixed saving and modifying parts 2025-08-25 19:39:53 +04:00
kapsona777 a87423d879 fixed saving and modifying parts 2025-08-25 18:08:33 +04:00
kapsona777 24cda34681 added feature to update inserted information, fixed bug that was inserting new rows after each refresh of the page and optimized get_customfield_values , it was sending many requests and optimized to 1. 2025-08-21 20:39:31 +04:00
solocla 2c514a8ab6 added button on top page for historical 2025-08-21 11:38:23 +02:00
solocla b1ea728c15 added main field functionality 2025-08-21 09:27:21 +02:00
solocla caf5568779 git ignore edit 2025-08-20 17:37:22 +02:00
solocla 0728fd8f01 update main field and git ignore 2025-08-20 17:30:13 +02:00
kapsona777 9d5c20113f fixed arrows 2025-08-20 17:45:21 +04:00
kapsona777 47762a8557 added feature about unsaved changes 2025-08-20 16:49:10 +04:00
solocla 434bb0d993 added fill dropdown and save id 2025-08-19 16:33:11 +02:00
kapsona777 939a4fe03e added feature to save image into database and after upload it can be chose by dropdown 2025-08-18 19:45:38 +04:00
kapsona777 493de65892 fixed saving annotated photos 2025-08-18 19:02:57 +04:00
kapsona777 23ae8e1b1d fixed displaying photo 2025-08-18 14:31:58 +04:00
kapsona777 7ad20993d9 added controller for QR photo upload and inserted route for it. added functional for multiple photo upload. 2025-08-11 16:30:24 +04:00
163 changed files with 67989 additions and 23634 deletions
-45
View File
@@ -1,45 +0,0 @@
APP_ENV=production
APP_DEBUG=true
APP_KEY=base64:C+sutHm6xP5sE4QXhoZFhYjArlVN11s2mDU1F8beUkM=
APP_URL=http://vanguard.test
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST="localhost"
DB_DATABASE="trfcertest"
DB_USERNAME="solocla"
DB_PASSWORD="!Massarosa2"
DB_PREFIX="auth_"
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_DRIVER=sync
SESSION_DRIVER=database
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=mail
MAIL_FROM_NAME=Vanguard
MAIL_FROM_ADDRESS=vanguard@test.dev
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Credenziali API VisualLims
API_BASE_URL=https://93.43.5.102/limsapi
API_USERNAME=WebApiUser
API_PASSWORD=webapiuser01
+14 -7
View File
@@ -1,16 +1,16 @@
APP_ENV=production
APP_DEBUG=false
APP_KEY=
APP_DEBUG=true
APP_KEY=base64:C+sutHm6xP5sE4QXhoZFhYjArlVN11s2mDU1F8beUkM=
APP_URL=http://vanguard.test
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=localhost
DB_DATABASE=vanguard
DB_USERNAME=homestead
DB_PASSWORD=secret
DB_PREFIX=vg_
DB_HOST="localhost"
DB_DATABASE="xxxx"
DB_USERNAME="xxxx"
DB_PASSWORD="xxxxx"
DB_PREFIX="auth_"
BROADCAST_DRIVER=log
CACHE_DRIVER=file
@@ -39,3 +39,10 @@ PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Credenziali API VisualLims
SIMULATE_EXPORT_LIMS=true
API_BASE_URL=https://bvcpsitaly-elims.com/limsapi
API_USERNAME=WebApiUser
API_PASSWORD=webapiuser01
BASE_URL=http://localhost:8000/userarea/
+33 -16
View File
@@ -1,38 +1,55 @@
.DS_Store
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
/.idea
/.fleet
/.vscode
/.vagrant
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
.env
.phpunit.result.cache
.php_cs.cache
/documentation
/.phpunit.cache
/public/hot
/public/storage
/public/build
/storage/*.key
.env
.env.backup
.env.production
auth.json
# File di debug e temporanei JSON e log
.phpunit.result.cache
.php_cs.cache
/.phpunit.cache
npm-debug.log
yarn-error.log
/documentation
# --- Runtime / Debug (userarea) ---
/public/userarea/*.json
/public/userarea/*.log
/public/userarea/*.txt
# File di log nella sottocartella class
/public/userarea/*_response.json
/public/userarea/error_log.txt
/public/userarea/import_debug.log
/public/userarea/last_url.txt
/public/userarea/logaspi/
/public/userarea/logsapi/
/public/userarea/photostrf/
/public/userarea/class/*.log
/public/userarea/class/curl_auth_debug.log
/public/userarea/class/curl_request_debug.log
# File XLSX temporanei importati
/public/userarea/imported_trf/*.xlsx
/public/userarea/xlstemplates/*.xlsx
# Ignora cartelle di foto generate
# Cartelle foto generate
/public/photostrf/
/public/photostrf/qrcodes/
# Ignora tutti i log ovunque
*.log
@@ -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']);
}
}
+12 -1
View File
@@ -28,10 +28,21 @@ class AppServiceProvider extends ServiceProvider
\Illuminate\Database\Schema\Builder::defaultStringLength(191);
Factory::guessFactoryNamesUsing(function (string $modelName) {
return 'Database\Factories\\'.class_basename($modelName).'Factory';
return 'Database\Factories\\' . class_basename($modelName) . 'Factory';
});
\Illuminate\Pagination\Paginator::useBootstrap();
// Register Microsoft Socialite driver
$this->app->make('Laravel\Socialite\Contracts\Factory')->extend('microsoft', function ($app) {
$config = $app['config']['services.microsoft'];
return new \SocialiteProviders\Microsoft\Provider(
$app['request'],
$config['client_id'],
$config['client_secret'],
$config['redirect']
);
});
}
/**
+3
View File
@@ -34,6 +34,9 @@ class EventServiceProvider extends ServiceProvider
Verified::class => [
ActivateUser::class,
],
\SocialiteProviders\Manager\SocialiteWasMapped::class => [
\SocialiteProviders\Microsoft\MicrosoftExtendSocialite::class,
],
];
/**
+1 -1
View File
@@ -12,7 +12,7 @@
*/
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
realpath(__DIR__ . '/../')
);
/*
+2 -1
View File
@@ -38,12 +38,13 @@
"laravel/fortify": "^1.21",
"laravel/framework": "^11.0",
"laravel/sanctum": "^4.0",
"laravel/socialite": "^5.0",
"laravel/socialite": "^5.16",
"laravel/tinker": "^2.7",
"laravel/ui": "^4.0",
"phpmailer/phpmailer": "^6.9",
"phpoffice/phpspreadsheet": "^4.1",
"proengsoft/laravel-jsvalidation": "^4.0.0",
"socialiteproviders/microsoft": "^4.7",
"spatie/laravel-query-builder": "^5.0",
"vanguardapp/activity-log": "^6.0",
"vanguardapp/announcements": "^6.0",
Generated
+138 -13
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ef3e05e7260284f5b7c7b4b6f93b252b",
"content-hash": "9c4f1e3bc3ee2180211c055e70635aef",
"packages": [
{
"name": "akaunting/laravel-setting",
@@ -2240,16 +2240,16 @@
},
{
"name": "laravel/socialite",
"version": "v5.15.1",
"version": "v5.16.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/socialite.git",
"reference": "cc02625f0bd1f95dc3688eb041cce0f1e709d029"
"reference": "40a2dc98c53d9dc6d55eadb0d490d3d72b73f1bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/cc02625f0bd1f95dc3688eb041cce0f1e709d029",
"reference": "cc02625f0bd1f95dc3688eb041cce0f1e709d029",
"url": "https://api.github.com/repos/laravel/socialite/zipball/40a2dc98c53d9dc6d55eadb0d490d3d72b73f1bf",
"reference": "40a2dc98c53d9dc6d55eadb0d490d3d72b73f1bf",
"shasum": ""
},
"require": {
@@ -2271,16 +2271,16 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Socialite\\SocialiteServiceProvider"
],
"aliases": {
"Socialite": "Laravel\\Socialite\\Facades\\Socialite"
}
},
"providers": [
"Laravel\\Socialite\\SocialiteServiceProvider"
]
},
"branch-alias": {
"dev-master": "5.x-dev"
}
},
"autoload": {
@@ -2308,7 +2308,7 @@
"issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite"
},
"time": "2024-06-28T20:09:34+00:00"
"time": "2024-09-03T09:46:57+00:00"
},
{
"name": "laravel/tinker",
@@ -4980,6 +4980,131 @@
],
"time": "2024-04-27T21:32:50+00:00"
},
{
"name": "socialiteproviders/manager",
"version": "v4.8.1",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Manager.git",
"reference": "8180ec14bef230ec2351cff993d5d2d7ca470ef4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/8180ec14bef230ec2351cff993d5d2d7ca470ef4",
"reference": "8180ec14bef230ec2351cff993d5d2d7ca470ef4",
"shasum": ""
},
"require": {
"illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
"laravel/socialite": "^5.5",
"php": "^8.1"
},
"require-dev": {
"mockery/mockery": "^1.2",
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"SocialiteProviders\\Manager\\ServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"SocialiteProviders\\Manager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Andy Wendt",
"email": "andy@awendt.com"
},
{
"name": "Anton Komarev",
"email": "a.komarev@cybercog.su"
},
{
"name": "Miguel Piedrafita",
"email": "soy@miguelpiedrafita.com"
},
{
"name": "atymic",
"email": "atymicq@gmail.com",
"homepage": "https://atymic.dev"
}
],
"description": "Easily add new or override built-in providers in Laravel Socialite.",
"homepage": "https://socialiteproviders.com",
"keywords": [
"laravel",
"manager",
"oauth",
"providers",
"socialite"
],
"support": {
"issues": "https://github.com/socialiteproviders/manager/issues",
"source": "https://github.com/socialiteproviders/manager"
},
"time": "2025-02-24T19:33:30+00:00"
},
{
"name": "socialiteproviders/microsoft",
"version": "4.7.0",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Microsoft.git",
"reference": "824ef97a4f6e3f363c21702b76676d54e8265573"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Microsoft/zipball/824ef97a4f6e3f363c21702b76676d54e8265573",
"reference": "824ef97a4f6e3f363c21702b76676d54e8265573",
"shasum": ""
},
"require": {
"ext-json": "*",
"firebase/php-jwt": "^6.8",
"php": "^8.0",
"socialiteproviders/manager": "^4.4"
},
"type": "library",
"autoload": {
"psr-4": {
"SocialiteProviders\\Microsoft\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brian Faust",
"email": "hello@brianfaust.de"
}
],
"description": "Microsoft OAuth2 Provider for Laravel Socialite",
"keywords": [
"laravel",
"microsoft",
"oauth",
"provider",
"socialite"
],
"support": {
"docs": "https://socialiteproviders.com/microsoft",
"issues": "https://github.com/socialiteproviders/providers/issues",
"source": "https://github.com/socialiteproviders/providers"
},
"time": "2025-07-06T00:25:25+00:00"
},
{
"name": "spatie/laravel-package-tools",
"version": "1.16.4",
+1
View File
@@ -228,6 +228,7 @@ return [
Proengsoft\JsValidation\JsValidationServiceProvider::class,
Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class,
Laravel\Socialite\SocialiteServiceProvider::class,
\SocialiteProviders\Manager\ServiceProvider::class,
Webpatser\Countries\CountriesServiceProvider::class,
Intervention\Image\ImageServiceProvider::class,
Jenssegers\Agent\AgentServiceProvider::class,
+3 -3
View File
@@ -11,9 +11,9 @@ return [
|
*/
// 'social' => [
// 'providers' => ['facebook', 'twitter', 'google'],
// ],
'social' => [
'providers' => ['microsoft'],
],
/*
|--------------------------------------------------------------------------
+9 -3
View File
@@ -64,9 +64,15 @@ return [
'redirect' => env('GOOGLE_CALLBACK_URI'),
],
// 'authy' => [
// 'key' => env('AUTHY_KEY'),
// ],
'microsoft' => [
'client_id' => env('MICROSOFT_CLIENT_ID'),
'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
'redirect' => env('MICROSOFT_REDIRECT_URI'),
],
// 'authy' => [
// 'key' => env('AUTHY_KEY'),
// ],
'resend' => [
'key' => env('RESEND_KEY'),
+1
View File
@@ -32,3 +32,4 @@ $langdatatables = [
"paginate_next" => "Next",
"paginate_previous" => "Previous"
];
$quotationstitle = "Quotations";
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

View File
+91
View File
@@ -0,0 +1,91 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
error_reporting(E_ALL);
require_once(__DIR__ . '/include/headscript.php'); // Auth + $iduserlogin + DBHandlerSelect
try {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
throw new Exception('Invalid request method');
}
$iddatadb = isset($_POST['iddatadb']) ? (int)$_POST['iddatadb'] : 0;
if ($iddatadb <= 0) {
throw new Exception('Missing iddatadb');
}
// ✅ Supporta sia singola stringa (con |) che array part_descriptions[]
$parts = [];
if (isset($_POST['part_descriptions']) && is_array($_POST['part_descriptions'])) {
$parts = $_POST['part_descriptions'];
} else {
$raw = isset($_POST['part_description']) ? (string)$_POST['part_description'] : '';
// split su "|" per multi-part
$parts = preg_split('/\s*\|\s*/', $raw);
}
// normalizza: trim + rimuovi vuoti + dedup
$cleanParts = [];
foreach ($parts as $p) {
$p = trim((string)$p);
if ($p === '') continue;
// limita lunghezza come da DB varchar(255)
if (mb_strlen($p) > 255) {
$p = mb_substr($p, 0, 255);
}
$cleanParts[] = $p;
}
$cleanParts = array_values(array_unique($cleanParts));
if (count($cleanParts) === 0) {
throw new Exception('Part description is empty');
}
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$pdo->beginTransaction();
try {
// prende il prossimo part_number per iddatadb
$stmtMax = $pdo->prepare("SELECT COALESCE(MAX(part_number), 0) AS maxnum FROM identification_parts WHERE iddatadb = ?");
$stmtMax->execute([$iddatadb]);
$nextNumber = (int)$stmtMax->fetchColumn() + 1;
$stmtIns = $pdo->prepare("
INSERT INTO identification_parts (iddatadb, part_number, part_description)
VALUES (?, ?, ?)
");
$insertedIds = [];
foreach ($cleanParts as $p) {
$ok = $stmtIns->execute([$iddatadb, $nextNumber, $p]);
if (!$ok) {
throw new Exception('Insert failed');
}
$insertedIds[] = $pdo->lastInsertId();
$nextNumber++;
}
$pdo->commit();
echo json_encode([
'success' => true,
'message' => 'Parts added',
'count' => count($insertedIds),
'ids' => $insertedIds
]);
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
throw $e;
}
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
exit;
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
<?php
ob_start();
session_start();
require_once '../../vendor/autoload.php';
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'excel_data' => []];
try {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$template_id = isset($input['template_id']) ? intval($input['template_id']) : 0;
$filename = $input['routine_data']['filename'] ?? '';
$headerrow = $input['routine_data']['headerrow'] ?? 1;
$excelData = $input['excel_data'] ?? [];
$routineData = $input['routine_data'] ?? [];
if (!$filename || empty($excelData)) {
throw new Exception("Dati della routine mancanti.");
}
$routineFile = __DIR__ . '/routines/' . $filename;
if (file_exists($routineFile)) {
include_once $routineFile;
$routineData['xls_headers'] = $_SESSION['headers'] ?? [];
applyRoutine($excelData, $routineData); // Modifica $excelData in place
error_log("Routine {$routineData['name']} applicata (file: {$filename}) per template {$template_id}, header row: {$headerrow}");
} else {
throw new Exception("File della routine non trovato: $routineFile");
}
// Aggiorna la sessione con i dati modificati
$_SESSION['excel_data'] = $excelData;
$response['excel_data'] = $excelData;
$response['rows'] = array_column($excelData, 'data');
$response['columns'] = $_SESSION['headers'];
$response['template_id'] = $template_id;
$response['filename'] = $input['filename'] ?? '';
} else {
$response['error'] = "Richiesta non valida.";
}
} catch (Exception $e) {
$response['error'] = "Errore durante l'applicazione della routine: " . $e->getMessage();
error_log("Exception in apply_routine.php: " . $e->getMessage());
}
ob_end_clean();
header('Content-Type: application/json');
echo json_encode($response);
exit;
+131
View File
@@ -0,0 +1,131 @@
<?php
require_once "class/VisualLimsApiClient.class.php";
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
header("Content-Type: application/json");
// 🔹 Configura directory log (creala se non esiste)
$logDir = __DIR__ . '/logs/api/';
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
// 🔹 Base URL API
$apiBaseUrl = 'https://93.43.5.102/limsapi/api/odata/';
// 🔹 Hardcoded values
$iddatadb = 846;
$commessaId = 533357;
try {
// 🔹 STEP 4: Fetch Field Values with Labels (usa dati reali per iddatadb=845)
$stmt = $pdo->prepare("
SELECT
idd.field_value,
m.field_label,
m.schema_id,
m.field_id
FROM
import_data_details as idd
JOIN template_mapping m ON idd.mapping_id = m.id
WHERE idd.id = :iddatadb
");
$stmt->execute(['iddatadb' => $iddatadb]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$fieldValues = [];
$valueMap = []; // Mappa per field_id -> valore
foreach ($rows as $row) {
$fieldValues[] = [
"IdCommesseCustomFields" => (int) $row['field_id'],
"Valore" => $row['field_value'],
"FieldLabel" => $row['field_label']
];
$valueMap[(int) $row['field_id']] = $row['field_value']; // Mappa per ID definizione
}
// Logga i fieldValues in error_log
$logFieldValues = "FieldValues dal DB (iddatadb={$iddatadb}):\n" . json_encode($fieldValues, JSON_PRETTY_PRINT);
error_log($logFieldValues);
// 🔹 Initialize API client
$api = VisualLimsApiClient::getInstance();
// 🔹 STEP A: GET iniziale per CommesseCustomFields con espansione CustomField
$expand = "CommesseCustomFields(\$expand=CustomField)"; // Espansione come da istruzioni fornitore
$commessaWithFields = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand);
// 🔹 STEP B: Prepara payload PATCH (tutti i campi, sovrascrivi se match su CustomField.IdCustomField == field_id)
$commessaCustomFields = [];
foreach ($commessaWithFields["CommesseCustomFields"] as $customField) {
$definitionId = (int) ($customField["CustomField"]["IdCustomField"] ?? 0); // Usa IdCustomField dal CustomField
$currentValue = $customField["Valore"] ?? '';
$newValue = isset($valueMap[$definitionId]) ? $valueMap[$definitionId] : $currentValue;
$commessaCustomFields[] = [
"IdCommesseCustomFields" => (int) $customField["IdCommesseCustomFields"],
"Valore" => $newValue
];
}
// 🔹 Unico file di log per tutto
$logFile = $logDir . "commessa_{$commessaId}_patch_and_get_" . time() . ".txt";
$logContent = "FieldValues dal DB (iddatadb={$iddatadb}):\n" . json_encode($fieldValues, JSON_PRETTY_PRINT) . "\n\n";
// Log curl-like per GET iniziale
$logContent .= "GET iniziale:\n" .
"curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
"--header 'Authorization: Bearer ••••••'\n\n" .
"RESPONSE:\n" . json_encode($commessaWithFields, JSON_PRETTY_PRINT) . "\n\n---\n";
if (!empty($commessaCustomFields)) {
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields];
// Log curl-like per PATCH
$jsonPayload = json_encode($updatePayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContent .= "PATCH:\n" .
"curl --location --request PATCH '{$apiBaseUrl}CommessaWeb({$commessaId})' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'\n\n";
$patchResponse = $api->patch("CommessaWeb({$commessaId})", $updatePayload);
$logContent .= "PATCH RESPONSE:\n" . json_encode($patchResponse, JSON_PRETTY_PRINT) . "\n\n---\n";
} else {
$logContent .= "PATCH: Nessun campo custom da aggiornare\n\n---\n";
}
// 🔹 STEP C: GET di controllo post-PATCH
$commessaAfterPatch = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand);
// Log curl-like per GET di controllo
$logContent .= "GET di controllo:\n" .
"curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
"--header 'Authorization: Bearer ••••••'\n\n" .
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
// Salva log unico
file_put_contents($logFile, $logContent);
// 🔹 Output a schermo
echo json_encode([
"success" => true,
"message" => "PATCH eseguito su commessa {$commessaId} con dati da iddatadb {$iddatadb}",
"commessaAfterPatch" => $commessaAfterPatch,
"totalCustomFieldsUpdated" => count($commessaCustomFields),
"fieldValues" => $fieldValues,
"logFile" => $logFile
]);
} catch (Exception $e) {
error_log("Patch Error: " . $e->getMessage() . "\nTrace: " . $e->getTraceAsString());
echo json_encode([
"success" => false,
"message" => "Patch failed: " . $e->getMessage(),
"logFile" => $logFile ?? 'Nessun log generato'
]);
}
@@ -24,12 +24,22 @@ class VisualLimsApiClient
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new VisualLimsApiClient();
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3));
$dotenv->load();
$simulate = ($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true';
if ($simulate) {
require_once __DIR__ . '/VisualLimsApiClientMock.class.php';
self::$instance = new VisualLimsApiClientMock();
} else {
self::$instance = new VisualLimsApiClient();
}
}
return self::$instance;
}
private function authenticate()
private function authenticate($retryCount = 0, $maxRetries = 3)
{
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@@ -45,16 +55,22 @@ class VisualLimsApiClient
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.log', 'w') ?: fopen('php://stderr', 'w');
$log = fopen(__DIR__ . '/curl_auth_debug.log', 'a') ?: 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);
$log_message = date('Y-m-d H:i:s') . " - Auth attempt {$retryCount}: HTTP {$http_code}, Error: {$curl_error}, Response: " . substr($response, 0, 1000) . "\n";
fwrite($log, $log_message);
fclose($log);
curl_close($ch);
if ($response === false || $http_code != 200) {
if ($http_code === 400 && strpos($response, 'Cannot persist the object') !== false && $retryCount < $maxRetries) {
usleep(500000); // Ritardo di 500ms
return $this->authenticate($retryCount + 1, $maxRetries); // Riprova
}
throw new Exception("Autenticazione fallita: HTTP {$http_code}, Errore cURL: {$curl_error}, Risposta: " . substr($response, 0, 1000));
}
@@ -120,4 +136,122 @@ class VisualLimsApiClient
return $data;
}
public function post($endpoint, $payload)
{
$token = $this->getToken();
$url = "{$this->baseUrl}/api/odata/{$endpoint}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$token}",
"Content-Type: application/json",
"Accept: application/json"
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);
if ($response === false) {
throw new Exception("Errore nella richiesta POST: {$curl_error}");
}
if ($http_code < 200 || $http_code >= 300) {
throw new Exception("POST fallito: HTTP {$http_code}, Risposta: " . substr($response, 0, 1000));
}
return json_decode($response, true);
}
public function patch($endpoint, $payload)
{
$token = $this->getToken();
$url = "{$this->baseUrl}/api/odata/{$endpoint}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$token}",
"Content-Type: application/json",
"Accept: application/json"
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);
if ($response === false) {
throw new Exception("Errore nella richiesta PATCH: {$curl_error}");
}
if ($http_code < 200 || $http_code >= 300) {
throw new Exception("PATCH fallito: HTTP {$http_code}, Risposta: " . substr($response, 0, 1000));
}
return json_decode($response, true);
}
/**
* POST a file as multipart/form-data (used for photo/attachment uploads).
*
* @param string $endpoint OData endpoint, e.g. "Campione(613388)/UploadCampioneFile"
* @param string $filePath Absolute path to the file on disk
* @param string $fileName Original file name to send
* @return array|null Decoded JSON response
*/
public function postMultipart($endpoint, $filePath, $fileName)
{
$token = $this->getToken();
$url = "{$this->baseUrl}/api/odata/{$endpoint}";
$cfile = new CURLFile($filePath, mime_content_type($filePath) ?: 'application/octet-stream', $fileName);
$payload = [
'file' => $cfile,
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$token}",
"Accept: application/json",
// Content-Type is set automatically to multipart/form-data by cURL
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);
if ($response === false) {
throw new Exception("Errore nella richiesta POST multipart: {$curl_error}");
}
if ($http_code < 200 || $http_code >= 300) {
throw new Exception("POST multipart fallito: HTTP {$http_code}, Risposta: " . substr($response, 0, 1000));
}
return json_decode($response, true);
}
public function getBaseUrl()
{
return $this->baseUrl;
}
}
@@ -0,0 +1,135 @@
<?php
/**
* Mock implementation of VisualLimsApiClient.
* Activated when SIMULATE_EXPORT_LIMS=true in .env.
* All HTTP calls are skipped; fake but structurally valid data is returned.
* Every simulated call is logged via error_log() with a [SIMULATE] prefix.
*/
class VisualLimsApiClientMock
{
private int $fakeCommessaId;
public function __construct()
{
// Stable fake ID for the lifetime of a single request
$this->fakeCommessaId = mt_rand(90001, 99999);
error_log("[SIMULATE] VisualLimsApiClientMock initialised (fakeCommessaId={$this->fakeCommessaId})");
}
public function get(string $endpoint): array
{
error_log("[SIMULATE] GET {$endpoint}");
// --- Fixed-field dropdown lists ---
if (str_starts_with($endpoint, 'MoltiplicatorePrezzi')) {
return ['value' => [
['IdMoltiplicatorePrezzo' => 1, 'Codice' => 'MP-01', 'Descrizione' => 'Standard (1x)'],
['IdMoltiplicatorePrezzo' => 2, 'Codice' => 'MP-02', 'Descrizione' => 'Urgente (1.5x)'],
['IdMoltiplicatorePrezzo' => 3, 'Codice' => 'MP-03', 'Descrizione' => 'Extra Urgente (2x)'],
]];
}
if (str_starts_with($endpoint, 'AnagraficaCertestObject')) {
return ['value' => [
['IdAnagrafica' => 1, 'Codice' => 'OBJ-01', 'NomeAnagrafica' => 'Articolo Tessile'],
['IdAnagrafica' => 2, 'Codice' => 'OBJ-02', 'NomeAnagrafica' => 'Componente Meccanico'],
['IdAnagrafica' => 3, 'Codice' => 'OBJ-03', 'NomeAnagrafica' => 'Materiale Plastico'],
]];
}
if (str_starts_with($endpoint, 'AnagraficaCertestService')) {
return ['value' => [
['IdAnagrafica' => 1, 'Codice' => 'SRV-01', 'NomeAnagrafica' => 'Analisi Chimica'],
['IdAnagrafica' => 2, 'Codice' => 'SRV-02', 'NomeAnagrafica' => 'Test Meccanico'],
['IdAnagrafica' => 3, 'Codice' => 'SRV-03', 'NomeAnagrafica' => 'Prova Ambientale'],
]];
}
// Cliente? list — get_clienti.php exits early in simulate mode, but guard here too
if (str_starts_with($endpoint, 'Cliente?')) {
return ['value' => []];
}
// Cliente(N)?$expand=Responsabili
if (str_starts_with($endpoint, 'Cliente(')) {
preg_match('/Cliente\((\d+)\)/', $endpoint, $m);
$clienteId = isset($m[1]) ? (int) $m[1] : 0;
return [
'IdCliente' => $clienteId,
'Responsabili' => [
['IdClienteResponsabile' => 1, 'Nominativo' => 'Marco Bianchi'],
['IdClienteResponsabile' => 2, 'Nominativo' => 'Giulia Ferrari'],
['IdClienteResponsabile' => 3, 'Nominativo' => 'Andrea Russo'],
],
];
}
// --- CustomField dropdown values (get_customfield_values.php) ---
if (str_starts_with($endpoint, 'CustomField(')) {
preg_match('/CustomField\((\d+)\)/', $endpoint, $m);
$fieldId = isset($m[1]) ? (int) $m[1] : 0;
return [
'CustomFieldsValues' => [
['IdCustomFieldsValue' => $fieldId * 10 + 1, 'Valore' => 'Opzione A'],
['IdCustomFieldsValue' => $fieldId * 10 + 2, 'Valore' => 'Opzione B'],
['IdCustomFieldsValue' => $fieldId * 10 + 3, 'Valore' => 'Opzione C'],
],
];
}
// --- CommessaWeb OData calls (STEP 7 GET + STEP 10 verification) ---
preg_match('/\((\d+)\)/', $endpoint, $m);
$id = isset($m[1]) ? (int) $m[1] : $this->fakeCommessaId;
return [
'IdCommessa' => $id,
'CodiceCommessa' => "SIM-{$id}",
'CommesseCustomFields' => [], // Empty → PATCH step is skipped correctly
];
}
public function post(string $endpoint, array $payload): array
{
error_log("[SIMULATE] POST {$endpoint} payload=" . json_encode($payload));
// CommessaWeb creation
if ($endpoint === 'CommessaWeb') {
return [
'IdCommessa' => $this->fakeCommessaId,
'CodiceCommessa' => "SIM-{$this->fakeCommessaId}",
'Richiedente' => $payload['Richiedente'] ?? '',
'Descrizione' => $payload['Descrizione'] ?? '',
];
}
// Campione creation
if ($endpoint === 'Campione') {
return [
'IdCampione' => mt_rand(10001, 19999),
'Commessa' => $payload['Commessa'] ?? null,
'Matrice' => $payload['Matrice'] ?? null,
];
}
// InviaCommessa / ImportaCommessa (currently commented out upstream)
return ['simulated' => true, 'endpoint' => $endpoint];
}
public function patch(string $endpoint, array $payload): array
{
error_log("[SIMULATE] PATCH {$endpoint} payload=" . json_encode($payload));
return [];
}
public function postMultipart(string $endpoint, string $filePath, string $fileName): array
{
error_log("[SIMULATE] POST multipart {$endpoint} file={$fileName}");
return ['simulated' => true, 'file' => $fileName];
}
}
@@ -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;
}
}
-36
View File
@@ -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: Thu, 21 Aug 2025 10:23:44 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/CustomField(1083)?$expand=CustomFieldsValues
* [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/CustomField(1083)?$expand=CustomFieldsValues]
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NTc3OTAyNSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.bBV1z1uaxZeUuw-2YS2gLGaxTCQJAHTieM82KVJb5nw]
* [HTTP/2] [1] [accept: application/json]
> GET /limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues HTTP/2
Host: 93.43.5.102
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NTc3OTAyNSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.bBV1z1uaxZeUuw-2YS2gLGaxTCQJAHTieM82KVJb5nw
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: Thu, 21 Aug 2025 10:23:44 GMT
<
* Connection #0 to host 93.43.5.102 left intact
File diff suppressed because one or more lines are too long
+77
View File
@@ -0,0 +1,77 @@
<?php
header('Content-Type: application/json');
require_once(__DIR__ . '/include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$input = json_decode(file_get_contents('php://input'), true);
$templateId = (int)($input['template_id'] ?? 0);
if ($templateId <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid template_id']);
exit;
}
// If already exists, do nothing
$stmt = $pdo->prepare("SELECT COUNT(*) FROM template_fixed_mapping WHERE template_id = ?");
$stmt->execute([$templateId]);
if ((int)$stmt->fetchColumn() > 0) {
echo json_encode(['success' => true, 'created' => 0, 'message' => 'Fixed fields already exist']);
exit;
}
/**
* FIXED FIELDS STANDARD (no UI selection)
* is_manual always 1
* is_visible_import default 1
*/
$fixedFields = [
// fixed_field_key, data_type
['ClienteResponsabile', 'INT'],
['MoltiplicatorePrezzo', 'INT'],
['AnagraficaCertestObject', 'INT'],
['AnagraficaCertestService', 'INT'],
['ConsegnaRichiesta', 'DATE'],
];
try {
$pdo->beginTransaction();
$ins = $pdo->prepare("
INSERT INTO template_fixed_mapping
(template_id, fixed_field_key, is_manual, data_type, is_required, default_value, is_visible_import)
VALUES
(:template_id, :fixed_field_key, 1, :data_type, 1, NULL, 1)
");
foreach ($fixedFields as $f) {
$ins->execute([
':template_id' => $templateId,
':fixed_field_key' => $f[0],
':data_type' => $f[1],
]);
}
$pdo->commit();
// Return rows (for client render)
$stmt = $pdo->prepare("
SELECT id, template_id, fixed_field_key, is_manual, data_type, is_required, default_value, is_visible_import
FROM template_fixed_mapping
WHERE template_id = ?
ORDER BY id ASC
");
$stmt->execute([$templateId]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(['success' => true, 'created' => count($rows), 'rows' => $rows]);
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
@@ -0,0 +1,103 @@
<?php
require_once dirname(__DIR__, 3) . '/vendor/autoload.php'; // Risale a root/vendor/
require_once dirname(__FILE__) . '/../class/VisualLimsApiClient.class.php'; // In root/public/userarea/class/
use Dotenv\Dotenv;
// Debug: Log the path where we expect the .env file
$envPath = dirname(__DIR__, 3);
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Expected .env path: ' . $envPath . PHP_EOL, FILE_APPEND);
// Carica il file .env dalla root del progetto
try {
$dotenv = Dotenv::createImmutable($envPath);
$dotenv->load();
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore caricamento .env: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
exit(1);
}
// Recupera le variabili d'ambiente
$dbHost = $_ENV['DB_HOST'];
$dbName = $_ENV['DB_DATABASE'];
$dbUser = $_ENV['DB_USERNAME'];
$dbPass = $_ENV['DB_PASSWORD'];
$dbPrefix = $_ENV['DB_PREFIX'];
// Debug: Log database connection details (excluding password)
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . " - DB Connection: host=$dbHost, dbname=$dbName, user=$dbUser, prefix=$dbPrefix" . PHP_EOL, FILE_APPEND);
// Connessione al database MySQL
try {
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore connessione DB: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
exit(1);
}
try {
$api = VisualLimsApiClient::getInstance();
// Endpoint per recuperare le Matrici
$endpoint = 'Matrice';
// (Opzionale) aggiungi parametri
$options = []; // es. ['$top' => 100]
// 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);
// Debug: Log the API response size
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - API response received, value count: ' . (isset($data['value']) ? count($data['value']) : 0) . PHP_EOL, FILE_APPEND);
// Salva il JSON in locale (opzionale, per debug)
file_put_contents(__DIR__ . '/matrici_response.json', json_encode($data, JSON_PRETTY_PRINT));
// Svuota la tabella (dump rapido)
$pdo->exec("TRUNCATE TABLE {$dbPrefix}matrici");
// Debug: Log after truncate
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Table truncated: ' . $dbPrefix . 'matrici' . PHP_EOL, FILE_APPEND);
// Prepara l'insert
$stmt = $pdo->prepare("
INSERT INTO {$dbPrefix}matrici (
IdMatrice, NomeMatriceTraduzione, DescrizioneTraduzione, MacroMatrice, NomeMatrice, Descrizione
) VALUES (
:IdMatrice, :NomeMatriceTraduzione, :DescrizioneTraduzione, :MacroMatrice, :NomeMatrice, :Descrizione
)
");
// Inserisci i dati
$insertedRows = 0;
if (isset($data['value']) && is_array($data['value'])) {
foreach ($data['value'] as $item) {
$stmt->execute([
':IdMatrice' => $item['IdMatrice'],
':NomeMatriceTraduzione' => $item['NomeMatriceTraduzione'],
':DescrizioneTraduzione' => $item['DescrizioneTraduzione'] ?? null,
':MacroMatrice' => $item['MacroMatrice'] ?? null,
':NomeMatrice' => $item['NomeMatrice'],
':Descrizione' => $item['Descrizione'] ?? null,
]);
$insertedRows++;
// Debug: Log each inserted row
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Inserted row with IdMatrice: ' . $item['IdMatrice'] . PHP_EOL, FILE_APPEND);
}
}
// Log successo
file_put_contents(__DIR__ . '/success_log.txt', date('Y-m-d H:i:s') . ' - Aggiornamento completato: ' . $insertedRows . ' record inseriti.' . PHP_EOL, FILE_APPEND);
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
exit(1);
}
exit(0); // Esci con successo per cron
-36
View File
@@ -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
-35
View File
@@ -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
-38
View File
@@ -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
-18
View File
@@ -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"
-35
View File
@@ -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
File diff suppressed because one or more lines are too long
-108
View File
@@ -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}
+28
View File
@@ -0,0 +1,28 @@
<?php
header('Content-Type: application/json');
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$data = json_decode(file_get_contents('php://input'), true);
$partId = $data['part_id'] ?? null;
if (!$partId) {
echo json_encode(['success' => false, 'message' => 'ID parte mancante']);
exit;
}
try {
$stmt = $pdo->prepare("DELETE FROM identification_parts WHERE id = :part_id");
$stmt->execute([':part_id' => $partId]);
$rowCount = $stmt->rowCount();
if ($rowCount > 0) {
echo json_encode(['success' => true, 'message' => 'Parte eliminata con successo']);
} else {
echo json_encode(['success' => false, 'message' => 'Nessuna parte trovata con ID ' . $partId]);
}
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nell\'eliminazione: ' . $e->getMessage()]);
}
Binary file not shown.
@@ -0,0 +1,23 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
@@ -0,0 +1 @@
3.0.34
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+139 -413
View File
@@ -20,17 +20,10 @@ if (!$template) {
exit;
}
// Debug del JSON
$clientSpecificFieldsJson = $template['client_specific_fields'] ?? '{}';
error_log("Raw client_specific_fields JSON: " . $clientSpecificFieldsJson);
$clientSpecificFields = json_decode($clientSpecificFieldsJson, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("JSON decode error: " . json_last_error_msg());
$clientSpecificFields = [];
} else {
error_log("Decoded client_specific_fields: " . print_r($clientSpecificFields, true));
}
// Recupera tutte le routine dal database
$stmt = $pdo->prepare("SELECT * FROM routine");
$stmt->execute();
$routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html lang="en">
@@ -41,28 +34,9 @@ if (json_last_error() !== JSON_ERROR_NONE) {
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<?php include('cssinclude.php'); ?>
<style>
.client-field-row .row {
margin-bottom: 0 !important;
display: flex;
align-items: center;
}
.client-field-row .col-md-1,
.client-field-row .col-md-2,
.client-field-row .col-md-3 {
padding: 0 5px;
overflow: hidden;
max-width: 100%;
flex: 0 0 auto;
}
.client-field-row input,
.client-field-row select {
width: 100%;
box-sizing: border-box;
}
</style>
<!-- Include jQuery prima di Select2 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<title>Edit Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head>
@@ -74,7 +48,7 @@ if (json_last_error() !== JSON_ERROR_NONE) {
<div class="page-content">
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">UpdateXLS Template</h5>
<h5 class="mb-0">Update XLS Template</h5>
</div>
<div class="card-body">
<p class="mb-2">Edit the following form in order to update the selected import XLS template</p>
@@ -82,7 +56,7 @@ if (json_last_error() !== JSON_ERROR_NONE) {
<ul class="mb-0">
<li>Template Name</li>
<li>Row Header and Column Header: where the title of the excel starts</li>
<li>Cheme</li>
<li>Schema</li>
</ul>
</div>
</div>
@@ -124,96 +98,67 @@ if (json_last_error() !== JSON_ERROR_NONE) {
<label class="form-label"><?= htmlspecialchars($desttable, ENT_QUOTES, 'UTF-8'); ?>*</label>
<input type="text" name="target_table" class="form-control" value="<?php echo htmlspecialchars($template['target_table']); ?>" readonly required>
</div>
<!-- Aggiungi il campo per selezionare il cliente -->
<div class="mb-3">
<label class="form-label">Button Size</label>
<select name="button_size" class="form-control">
<option value="small" <?php echo ($template['button_size'] ?? 'medium') === 'small' ? 'selected' : ''; ?>>Small</option>
<option value="medium" <?php echo ($template['button_size'] ?? 'medium') === 'medium' ? 'selected' : ''; ?>>Medium</option>
<option value="large" <?php echo ($template['button_size'] ?? 'medium') === 'large' ? 'selected' : ''; ?>>Large</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Button Background Color</label>
<input type="color" name="button_bg_color" class="form-control" value="<?php echo htmlspecialchars($template['button_bg_color'] ?? '#007bff'); ?>">
</div>
<div class="mb-3">
<label class="form-label">Button Text Color</label>
<input type="color" name="button_text_color" class="form-control" value="<?php echo htmlspecialchars($template['button_text_color'] ?? '#ffffff'); ?>">
</div>
<div class="mb-3">
<label class="form-label">Button Label</label>
<input type="text" name="button_label" class="form-control" value="<?php echo htmlspecialchars($template['button_label'] ?? 'Click Me'); ?>">
</div>
<div class="mb-3">
<label class="form-label">Select Client *</label>
<select name="client_id" id="clientSelect" class="form-control" required>
<option value="">Select a client...</option>
<!-- Le opzioni verranno popolate tramite JavaScript -->
</select>
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
</div>
<!-- Aggiungi il campo per selezionare lo schema -->
<div class="mb-3">
<label class="form-label">Select Schema *</label>
<select name="schema_id" id="schemaSelect" class="form-control" required>
<option value="">Select a schema...</option>
<!-- Le opzioni verranno popolate tramite JavaScript -->
</select>
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Caricamento schemi in corso...</span>
</div>
<!-- Sezione per i campi specifici del cliente -->
<div class="mb-3">
<label class="form-label">Client-Specific Fields</label>
<!-- Intestazioni colonne -->
<div class="row fw-bold text-secondary mb-1">
<div class="col-md-3">Field Name</div>
<div class="col-md-2">Type</div>
<div class="col-md-2">Possible Values</div>
<div class="col-md-1">Required</div>
<div class="col-md-2">Export Column Name</div>
<div class="col-md-1">Default Value</div>
<div class="col-md-1">Actions</div>
<label class="form-label">Select Routine</label>
<select name="idroutine" id="routineSelect" class="form-control">
<option value="">Select a routine...</option>
<?php foreach ($routines as $routine): ?>
<option value="<?php echo $routine['idroutine']; ?>" <?php echo ($template['idroutine'] ?? '') == $routine['idroutine'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($routine['name']); ?>
</option>
<?php endforeach; ?>
</select>
<div id="routineDetails" class="mt-2" style="display: none;">
<h6>Routine Details</h6>
<p><strong>Name:</strong> <span id="routineName"></span></p>
<p><strong>Description:</strong> <span id="routineDescription"></span></p>
<p><strong>Action 1:</strong> <span id="routineAction1"></span></p>
<p><strong>Action 2:</strong> <span id="routineAction2"></span></p>
<p><strong>Action 3:</strong> <span id="routineAction3"></span></p>
</div>
<div id="clientSpecificFields">
<?php
$index = 0;
if (!empty($clientSpecificFields) && is_array($clientSpecificFields)) {
foreach ($clientSpecificFields as $fieldName => $fieldData) {
if (is_array($fieldData)) {
$type = $fieldData['type'] ?? 'text';
$possibleValues = implode(', ', $fieldData['possible_values'] ?? []);
$isRequired = isset($fieldData['is_required']) && $fieldData['is_required'] ? '1' : '0';
$exportColumnName = $fieldData['export_column_name'] ?? '';
$defaultValue = $fieldData['default_value'] ?? '';
?>
<div class="client-field-row mb-2">
<div class="row align-items-center">
<div class="col-md-3">
<input type="text" name="specific_fields[<?php echo $index; ?>][name]" class="form-control" value="<?php echo htmlspecialchars($fieldName); ?>" placeholder="Field Name (e.g., SKU)">
</div>
<div class="col-md-2">
<select name="specific_fields[<?php echo $index; ?>][type]" class="form-control" onchange="toggleDropdownValues(this)">
<option value="text" <?php echo $type === 'text' ? 'selected' : ''; ?>>Text</option>
<option value="dropdown" <?php echo $type === 'dropdown' ? 'selected' : ''; ?>>Dropdown</option>
<option value="date" <?php echo $type === 'date' ? 'selected' : ''; ?>>Date</option>
<option value="boolean" <?php echo $type === 'boolean' ? 'selected' : ''; ?>>Yes/No</option>
</select>
</div>
<div class="col-md-2 dropdown-values" style="<?php echo $type === 'dropdown' ? 'visibility: visible;' : 'visibility: hidden;'; ?>">
<input type="text" name="specific_fields[<?php echo $index; ?>][possible_values]" class="form-control" value="<?php echo htmlspecialchars($possibleValues); ?>" placeholder="Values (e.g., Red, Blue, Green)">
</div>
<div class="col-md-1">
<select name="specific_fields[<?php echo $index; ?>][required]" class="form-control">
<option value="1" <?php echo $isRequired === '1' ? 'selected' : ''; ?>>Yes</option>
<option value="0" <?php echo $isRequired === '0' ? 'selected' : ''; ?>>No</option>
</select>
</div>
<div class="col-md-2">
<input type="text" name="specific_fields[<?php echo $index; ?>][export_column_name]" class="form-control" value="<?php echo htmlspecialchars($exportColumnName); ?>" placeholder="Export Column Name (e.g., MONCLER_SKU)">
</div>
<div class="col-md-1">
<input type="text" name="specific_fields[<?php echo $index; ?>][default_value]" class="form-control" value="<?php echo htmlspecialchars($defaultValue); ?>" placeholder="Default Value (optional)">
</div>
<div class="col-md-1">
<button type="button" class="btn btn-danger remove-field">-</button>
</div>
</div>
</div>
<?php
$index++;
}
}
}
?>
</div>
<button type="button" class="btn btn-primary mt-2" id="addField">Add Field</button>
</div>
<br>
<button type="submit" class="btn btn-primary"><?= htmlspecialchars($savechanges, ENT_QUOTES, 'UTF-8'); ?></button>
<a href="templates_dashboard.php" class="btn btn-secondary">Cancel</a>
@@ -223,132 +168,78 @@ if (json_last_error() !== JSON_ERROR_NONE) {
</div>
</div>
</div>
<!--end page wrapper -->
<!--start overlay-->
<div class="overlay toggle-icon"></div>
<!--end overlay-->
<!--Start Back To Top Button-->
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<!--End Back To Top Button-->
<?php include('include/footer.php'); ?>
</div>
<!--end wrapper-->
<!-- search modal -->
<?php //include('include/searchmodal.php');
?>
<!-- end search modal -->
<!--start switcher-->
<?php //include('include/themeswitcher.php');
?>
<!--end switcher-->
<!-- Temporaneamente disabilitato jsinclude.php per test -->
<!-- <?php include('jsinclude.php'); ?> -->
<!-- Includi jQuery e Select2 -->
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
// Dati del cliente e dello schema associati al template
const templateClientId = <?php echo json_encode($template['idclient'] ?? 0); ?>;
const templateSchemaId = <?php echo json_encode($template['idschema'] ?? 0); ?>;
const templateSchemaName = "<?php echo htmlspecialchars($template['schemaname'] ?? ''); ?>";
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Verifica che jQuery sia caricato
if (typeof jQuery === 'undefined') {
alert("Errore: jQuery non è caricato. Contatta l'amministratore.");
return;
}
const form = document.getElementById("editTemplateForm");
const addFieldButton = document.getElementById("addField");
const container = document.getElementById("clientSpecificFields");
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
const schemaLoadingStatus = document.getElementById("schemaLoadingStatus");
const routineSelect = document.getElementById("routineSelect");
const routineDetails = document.getElementById("routineDetails");
const routineName = document.getElementById("routineName");
const routineDescription = document.getElementById("routineDescription");
const routineAction1 = document.getElementById("routineAction1");
const routineAction2 = document.getElementById("routineAction2");
const routineAction3 = document.getElementById("routineAction3");
if (!form || !addFieldButton || !container || !clientLoadingStatus || !schemaLoadingStatus) {
console.error("One or more DOM elements not found:", {
form,
addFieldButton,
container,
clientLoadingStatus,
schemaLoadingStatus
});
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
return;
}
console.log("All DOM elements found");
// Controllo che jQuery sia caricato
if (typeof jQuery === 'undefined') {
console.error("jQuery non è caricato!");
return;
}
// Inizializza Select2 sulla tendina dei clienti
// Inizializza Select2
$('#clientSelect').select2({
placeholder: "Search for a client...",
allowClear: true
}).on('select2:open', function() {
console.log("Select2 initialized successfully for clientSelect");
}).on('select2:select', function(e) {
console.log("Client selected:", e.params.data.id, e.params.data.text);
});
// Inizializza Select2 sulla tendina degli schemi
$('#schemaSelect').select2({
placeholder: "Search for a schema...",
allowClear: true
}).on('select2:open', function() {
console.log("Select2 initialized successfully for schemaSelect");
}).on('select2:select', function(e) {
console.log("Schema selected:", e.params.data.id, e.params.data.text);
});
// Carica i clienti al caricamento della pagina
$('#routineSelect').select2({
placeholder: "Select a routine...",
allowClear: true
});
// Carica i clienti
async function loadClients() {
try {
clientLoadingStatus.style.display = 'inline';
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
const response = await fetch("get_clienti.php", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const text = await response.text();
console.log("Risposta raw (clienti):", text);
const data = JSON.parse(text);
if (!response.ok) {
throw new Error(data.error || `Errore HTTP: ${response.status}`);
}
if (data.value && Array.isArray(data.value)) {
const select = document.getElementById("clientSelect");
select.innerHTML = '<option value="">Select a client...</option>';
data.value.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
if (parseInt(id) === parseInt(templateClientId)) {
option.selected = true;
}
select.add(option);
});
$(select).trigger('change');
console.log("Clienti caricati con successo.");
clientLoadingStatus.textContent = "Clienti caricati.";
} else {
console.error("Nessun cliente trovato o formato dati non valido.", data);
clientLoadingStatus.textContent = "Nessun cliente trovato.";
Swal.fire({
title: "Errore!",
text: "Nessun cliente trovato o formato dati non valido.",
icon: "error",
confirmButtonText: "OK"
});
}
const data = await response.json();
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
const select = document.getElementById("clientSelect");
select.innerHTML = '<option value="">Select a client...</option>';
data.value.forEach(client => {
const nome = client.Nominativo || "Nome non disponibile";
const id = client.IdCliente || "ID non disponibile";
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($template['idclient'] ?? 0); ?>)) {
option.selected = true;
}
select.add(option);
});
$(select).trigger('change');
clientLoadingStatus.textContent = "Clienti caricati.";
} catch (error) {
console.error("Errore nel caricamento dei clienti:", error);
clientLoadingStatus.textContent = "Errore nel caricamento.";
Swal.fire({
title: "Errore!",
@@ -357,50 +248,37 @@ if (json_last_error() !== JSON_ERROR_NONE) {
confirmButtonText: "OK"
});
} finally {
setTimeout(() => {
clientLoadingStatus.style.display = 'none';
}, 2000);
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
}
}
// Carica gli schemi al caricamento della pagina
// Carica gli schemi
async function loadSchemas() {
try {
schemaLoadingStatus.style.display = 'inline';
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
const response = await fetch("get_schemi.php", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
});
const text = await response.text();
console.log("Risposta raw (schemi):", text);
const data = JSON.parse(text);
if (!response.ok) {
throw new Error(data.error || `Errore HTTP: ${response.status}`);
}
const data = await response.json();
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
const select = document.getElementById("schemaSelect");
select.innerHTML = '<option value="">Select a schema...</option>';
data.value.forEach(schema => {
const nome = schema.Nome || "Nome non disponibile";
const id = schema.IdSchemaCustomFields || "ID non disponibile";
const optionText = `${nome.trim()} (ID: ${id})`;
const option = new Option(optionText, id);
if (parseInt(id) === parseInt(templateSchemaId)) {
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
if (parseInt(id) === parseInt(<?php echo json_encode($template['idschema'] ?? 0); ?>)) {
option.selected = true;
}
select.add(option);
});
$(select).trigger('change');
console.log("Schemi caricati con successo.");
schemaLoadingStatus.textContent = "Schemi caricati.";
} catch (error) {
console.error("Errore nel caricamento degli schemi:", error);
schemaLoadingStatus.textContent = "Errore nel caricamento.";
Swal.fire({
title: "Errore!",
@@ -409,169 +287,68 @@ if (json_last_error() !== JSON_ERROR_NONE) {
confirmButtonText: "OK"
});
} finally {
setTimeout(() => {
schemaLoadingStatus.style.display = 'none';
}, 2000);
setTimeout(() => schemaLoadingStatus.style.display = 'none', 2000);
}
}
// Carica i dati in sequenza
// Carica i dati
async function loadData() {
try {
await loadClients();
await loadSchemas();
} catch (error) {
console.error("Errore nel caricamento dei dati:", error);
}
}
loadData();
// Debug iniziale del DOM
const debugDom = () => {
const initialRows = container.getElementsByClassName("client-field-row");
console.log("Initial number of rows:", initialRows.length);
for (let i = 0; i < initialRows.length; i++) {
const inputs = initialRows[i].querySelectorAll("input, select");
const buttons = initialRows[i].querySelectorAll("button");
console.log(`Row ${i + 1} - Total inputs: ${inputs.length}, Total buttons: ${buttons.length}`);
inputs.forEach(input => console.log(`Input name: ${input.name}, value: ${input.value}, placeholder: ${input.placeholder}`));
buttons.forEach(button => console.log(`Button type: ${button.type}`));
}
};
debugDom();
// Pulizia del DOM da input extra
const cleanDom = () => {
const rows = container.getElementsByClassName("client-field-row");
for (let i = 0; i < rows.length; i++) {
const inputs = rows[i].querySelectorAll("input, select");
if (inputs.length > 6) { // 6 input/select attesi
console.warn(`Row ${i + 1}: Extra inputs detected, removing excess...`);
inputs.forEach((input, index) => {
if (index >= 6) {
console.log(`Removing extra input: ${input.name}`);
input.remove();
}
});
}
}
};
cleanDom();
// Osservatore del DOM per rilevare modifiche
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.addedNodes.length) {
console.log("DOM modified: New nodes added", mutation.addedNodes);
cleanDom(); // Pulisce il DOM ogni volta che viene modificato
}
});
});
observer.observe(container, {
childList: true,
subtree: true
});
// Gestione dinamica dei campi specifici
addFieldButton.addEventListener("click", function() {
console.log("Add Field button clicked");
const fieldCount = container.getElementsByClassName("client-field-row").length;
const newField = document.createElement("div");
newField.className = "client-field-row mb-2";
newField.innerHTML = `
<div class="row align-items-center">
<div class="col-md-3">
<input type="text" name="specific_fields[${fieldCount}][name]" class="form-control" placeholder="Field Name (e.g., SKU)">
</div>
<div class="col-md-2">
<select name="specific_fields[${fieldCount}][type]" class="form-control" onchange="toggleDropdownValues(this)">
<option value="text">Text</option>
<option value="dropdown">Dropdown</option>
<option value="date">Date</option>
<option value="boolean">Yes/No</option>
</select>
</div>
<div class="col-md-2 dropdown-values" style="visibility: hidden;">
<input type="text" name="specific_fields[${fieldCount}][possible_values]" class="form-control" placeholder="Values (e.g., Red, Blue, Green)">
</div>
<div class="col-md-1">
<select name="specific_fields[${fieldCount}][required]" class="form-control">
<option value="1">Yes</option>
<option value="0">No</option>
</select>
</div>
<div class="col-md-2">
<input type="text" name="specific_fields[${fieldCount}][export_column_name]" class="form-control" placeholder="Export Column Name (e.g., MONCLER_SKU)">
</div>
<div class="col-md-1">
<input type="text" name="specific_fields[${fieldCount}][default_value]" class="form-control" placeholder="Default Value (optional)">
</div>
<div class="col-md-1">
<button type="button" class="btn btn-danger remove-field">-</button>
</div>
</div>
`;
container.appendChild(newField);
newField.querySelector(".remove-field").addEventListener("click", function() {
console.log("Remove Field button clicked");
container.removeChild(newField);
updateFieldIndices();
});
});
// Funzione per mostrare/nascondere il campo dei valori possibili per i dropdown
window.toggleDropdownValues = function(selectElement) {
console.log("Toggling dropdown values for:", selectElement.value);
const row = selectElement.closest(".row");
const dropdownValues = row.querySelector(".dropdown-values");
if (selectElement.value === "dropdown") {
dropdownValues.style.visibility = "visible";
} else {
dropdownValues.style.visibility = "hidden";
}
};
// Event listener per i pulsanti di rimozione esistenti
document.querySelectorAll(".remove-field").forEach(button => {
button.addEventListener("click", function() {
console.log("Existing remove button clicked");
const container = document.getElementById("clientSpecificFields");
container.removeChild(button.closest(".client-field-row"));
updateFieldIndices();
});
});
// Funzione per aggiornare gli indici dei campi
function updateFieldIndices() {
console.log("Updating field indices");
const rows = container.getElementsByClassName("client-field-row");
for (let i = 0; i < rows.length; i++) {
const inputs = rows[i].querySelectorAll("input, select");
inputs.forEach(input => {
const name = input.name.replace(/\[\d+\]/, `[${i}]`);
input.name = name;
Swal.fire({
title: "Errore!",
text: "Errore nel caricamento dei dati: " + error.message,
icon: "error",
confirmButtonText: "OK"
});
}
}
loadData();
// Routine dettagli
const routines = <?php echo json_encode($routines); ?>;
function updateRoutineDetails() {
const selectedId = routineSelect.value;
routineDetails.style.display = selectedId ? 'block' : 'none';
if (selectedId) {
const routine = routines.find(r => r.idroutine == selectedId);
if (routine) {
routineName.textContent = routine.name || 'N/A';
routineDescription.textContent = routine.description || 'N/A';
routineAction1.textContent = routine.action1 || 'N/A';
routineAction2.textContent = routine.action2 || 'N/A';
routineAction3.textContent = routine.action3 || 'N/A';
} else {
routineName.textContent = 'N/A';
routineDescription.textContent = 'N/A';
routineAction1.textContent = 'N/A';
routineAction2.textContent = 'N/A';
routineAction3.textContent = 'N/A';
}
} else {
routineName.textContent = '';
routineDescription.textContent = '';
routineAction1.textContent = '';
routineAction2.textContent = '';
routineAction3.textContent = '';
}
}
routineSelect.addEventListener('change', updateRoutineDetails);
updateRoutineDetails(); // Inizializza dettagli se una routine è preselezionata
// Submit del form
form.addEventListener("submit", function(e) {
e.preventDefault();
console.log("Form submitted");
let formData = new FormData(this);
// Aggiungi il nome del cliente selezionato a FormData
const clientSelect = document.getElementById("clientSelect");
const clientId = clientSelect.value;
const selectedClientOption = clientSelect.options[clientSelect.selectedIndex];
// Validazione: assicurati che un cliente sia selezionato
if (!clientId) {
Swal.fire({
title: "Errore!",
@@ -582,22 +359,18 @@ if (json_last_error() !== JSON_ERROR_NONE) {
return;
}
// Estrai il nome del cliente in modo più robusto
let clientName = "";
if (selectedClientOption) {
const optionText = selectedClientOption.text.trim();
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
clientName = nameMatch ? nameMatch[1].trim() : optionText;
}
formData.append("client_name", clientName);
// Aggiungi l'ID e il nome dello schema selezionato a FormData
const schemaSelect = document.getElementById("schemaSelect");
const schemaId = schemaSelect.value;
const selectedSchemaOption = schemaSelect.options[schemaSelect.selectedIndex];
// Validazione: assicurati che uno schema sia selezionato
if (!schemaId) {
Swal.fire({
title: "Errore!",
@@ -608,63 +381,18 @@ if (json_last_error() !== JSON_ERROR_NONE) {
return;
}
// Estrai il nome dello schema in modo più robusto
let schemaName = "";
if (selectedSchemaOption) {
const optionText = selectedSchemaOption.text.trim();
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
}
formData.append("idschema", schemaId);
formData.append("schemamaname", schemaName);
formData.append("schemaname", schemaName);
// Log per debug
console.log("Client ID:", clientId);
console.log("Client Name:", clientName);
console.log("Schema ID:", schemaId);
console.log("Schema Name:", schemaName);
// Genera il JSON per client_specific_fields
let finalSpecificFields = {};
// Raccolta dei dati direttamente dal DOM
const fieldRows = container.getElementsByClassName("client-field-row");
for (let i = 0; i < fieldRows.length; i++) {
const row = fieldRows[i];
const inputs = row.querySelectorAll("input, select");
let fieldData = {};
inputs.forEach(input => {
const nameMatch = input.name.match(/specific_fields\[\d+\]\[(.*?)\]/);
if (nameMatch) {
const fieldName = nameMatch[1];
fieldData[fieldName] = input.value.trim();
}
});
if (fieldData.name) {
finalSpecificFields[fieldData.name] = {
type: fieldData.type || "text",
possible_values: (fieldData.possible_values && fieldData.type === "dropdown") ? fieldData.possible_values.split(",").map(v => v.trim()) : [],
is_required: fieldData.required === "1",
export_column_name: fieldData.export_column_name || "",
default_value: fieldData.default_value || ""
};
console.log(`Field ${fieldData.name}:`, finalSpecificFields[fieldData.name]);
}
}
console.log("Generated JSON for client_specific_fields:", JSON.stringify(finalSpecificFields));
// Aggiungi il JSON al FormData
formData.append("client_specific_fields", JSON.stringify(finalSpecificFields));
// Debug del FormData
console.log("FormData contents:");
for (let pair of formData.entries()) {
console.log(pair[0] + ': ' + pair[1]);
}
// Aggiungi idroutine
const routineId = routineSelect.value;
formData.append("idroutine", routineId);
fetch("process_edit_template_xls.php", {
method: "POST",
@@ -672,7 +400,6 @@ if (json_last_error() !== JSON_ERROR_NONE) {
})
.then(response => response.json())
.then(data => {
console.log("Fetch response:", data);
if (data.success) {
Swal.fire({
title: "Successo!",
@@ -692,7 +419,6 @@ if (json_last_error() !== JSON_ERROR_NONE) {
}
})
.catch(error => {
console.error("Errore Fetch:", error);
Swal.fire({
title: "Errore!",
text: "Si è verificato un errore imprevisto.",
+307
View File
@@ -5,3 +5,310 @@
2025-07-04 10:42:49 - 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-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
2025-09-08 08:39:17 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
2026-01-27 15:33:53 - Errore nel recupero dati: HTTP 404, Risposta:
2026-01-27 15:34:06 - Errore nel recupero dati: HTTP 404, Risposta:
2026-01-27 15:34:10 - Errore nel recupero dati: HTTP 404, Risposta:
2026-01-27 15:35:13 - Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:33:38 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:33:39 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-01-29 14:34:04 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:37:29 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:41:55 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:42:03 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:42:52 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-29 14:43:00 [ClienteResponsabile] Errore nel recupero dati: HTTP 404, Risposta:
2026-01-30 10:50:43 [AnagraficaCertestService] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-01-30 10:50:43 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-01-30 11:09:22 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-02-19 10:00:13 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-02-19 10:00:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-02-19 10:00:44 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-02-23 10:44:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:42 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:43 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:43 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:43 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [MoltiplicatorePrezzo] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:52 [AnagraficaCertestObject] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:44:53 [AnagraficaCertestService] Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:48:26 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:48:26 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:48:27 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:48:27 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:48:27 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:49:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:49:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:49:04 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:49:05 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 10:49:05 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 14:26:52 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 14:26:59 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 15:54:16 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 16:22:45 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-23 16:32:17 - Autenticazione fallita: HTTP 404, Errore cURL: , Risposta: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
2026-02-25 15:23:12 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
2026-02-26 15:01:32 [AnagraficaCertestObject] Autenticazione fallita: HTTP 400, Errore cURL: , Risposta: {"title":"Bad Request","status":400,"detail":"Cannot persist the object. It was modified or deleted (purged) by another application.","instance":"POST /api/authentication/authenticate","errorCode":"96bfc1252b"}
+221
View File
@@ -0,0 +1,221 @@
document.addEventListener("DOMContentLoaded", () => {
console.log("export_to_lims.js loaded");
const exportButtons = document.querySelectorAll(".export-lims-btn");
console.log(`Found ${exportButtons.length} export-lims-btn buttons`);
if (exportButtons.length === 0) {
console.warn("No .export-lims-btn buttons found in the DOM");
return;
}
// Tracks the active confirm handler so it can be replaced on re-open
let pendingConfirmHandler = null;
// ── Helpers ──────────────────────────────────────────────────────────────
function cleanupBackdrop() {
document.querySelectorAll(".modal-backdrop").forEach((b) => b.remove());
document.body.classList.remove("modal-open");
document.body.style.paddingRight = "";
const overlay = document.querySelector(".overlay.toggle-icon");
if (overlay) overlay.style.display = "none";
}
// ── Step 2: show export-confirm modal, send on "Conferma" ────────────────
function startExportConfirmFlow(iddatadb, btn) {
const confirmModalElement = document.getElementById("exportConfirmModal");
if (!confirmModalElement) {
alert("Errore: Modale di conferma non trovato");
return;
}
const confirmModal = new bootstrap.Modal(confirmModalElement, {
keyboard: false,
});
document.getElementById("exportIddatadb").textContent = iddatadb;
confirmModal.show();
const confirmBtn = document.getElementById("exportConfirmBtn");
if (!confirmBtn) {
confirmModal.hide();
alert("Errore: Pulsante di conferma non trovato");
return;
}
const confirmHandler = async () => {
pendingConfirmHandler = null;
console.log(`Confirmed export for iddatadb: ${iddatadb}`);
confirmModal.hide();
const formData = new FormData();
formData.append("iddatadb", iddatadb);
try {
const response = await fetch("export_to_lims.php", {
method: "POST",
body: formData,
});
if (!response.ok)
throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
console.log("Export response:", data);
const responseModalElement =
document.getElementById("exportResponseModal");
if (!responseModalElement) {
alert("Errore: Modale di risposta non trovato");
return;
}
const responseModal = new bootstrap.Modal(
responseModalElement,
{ keyboard: false },
);
const responseMessage = document.getElementById(
"exportResponseMessage",
);
if (data.success) {
responseMessage.innerHTML =
`${data.message.replace(/\n/g, "<br>")}` +
`<br>ID CommessaWeb: ${data.idcommessaweb}` +
`<br>Codice CommessaWeb: ${data.commessaweb}` +
(data.totalPhotos > 0
? `<br>Foto trovate: ${data.totalPhotos}`
: "");
document.getElementById(
"exportResponseModalLabel",
).textContent = "Esportazione Completata";
responseModal.show();
// Update status badge
const gridRow = btn.closest(".grid-row");
const statusBadge = gridRow?.querySelector(
'.grid-cell[data-col="status"] .status-badge',
);
if (statusBadge) {
statusBadge.classList.remove("status-i", "status-P");
statusBadge.classList.add("status-l");
statusBadge.textContent = "To LIMS";
}
// Insert/update CommessaWeb code span
const statusCell = gridRow?.querySelector(
'.grid-cell[data-col="status"]',
);
if (statusCell && data.commessaweb) {
let cwSpan =
statusCell.querySelector(".commessaweb-code");
if (!cwSpan) {
cwSpan = document.createElement("span");
cwSpan.className = "commessaweb-code";
cwSpan.style.cssText =
"display:block; font-size:0.75em; color:#555; margin-top:2px;";
cwSpan.title = "CommessaWeb";
const hiddenInput = statusCell.querySelector(
'input[type="hidden"]',
);
hiddenInput
? statusCell.insertBefore(cwSpan, hiddenInput)
: statusCell.appendChild(cwSpan);
}
cwSpan.textContent = data.commessaweb;
}
} else {
responseMessage.textContent = `Errore durante la generazione dei payload: ${data.message}`;
document.getElementById(
"exportResponseModalLabel",
).textContent = "Errore Esportazione";
responseModal.show();
}
responseModalElement.addEventListener(
"hidden.bs.modal",
cleanupBackdrop,
{ once: true },
);
} catch (error) {
console.error("Export error:", error);
const responseModalElement =
document.getElementById("exportResponseModal");
if (!responseModalElement) {
alert("Errore: Modale di risposta non trovato");
return;
}
const responseModal = new bootstrap.Modal(
responseModalElement,
{ keyboard: false },
);
document.getElementById(
"exportResponseMessage",
).textContent = `Errore: ${error.message}`;
document.getElementById(
"exportResponseModalLabel",
).textContent = "Errore Esportazione";
responseModal.show();
responseModalElement.addEventListener(
"hidden.bs.modal",
cleanupBackdrop,
{ once: true },
);
}
};
if (pendingConfirmHandler) {
confirmBtn.removeEventListener("click", pendingConfirmHandler);
}
pendingConfirmHandler = confirmHandler;
confirmBtn.addEventListener("click", confirmHandler, { once: true });
}
// ── Step 1: check unsaved changes, save if needed, then export ───────────
exportButtons.forEach((btn) => {
btn.addEventListener("click", (e) => {
e.preventDefault();
const rowIndex = btn.dataset.row;
const iddatadb = btn.dataset.iddatadb;
console.log(
`Export to LIMS clicked for row ${rowIndex}, iddatadb: ${iddatadb}`,
);
const gridRow = btn.closest(".grid-row");
if (gridRow && gridRow.querySelector(".cell-changed")) {
const unsavedModal = new bootstrap.Modal(
document.getElementById("exportUnsavedModal"),
{ keyboard: false },
);
unsavedModal.show();
document.getElementById("saveAndExportBtn").addEventListener("click", () => {
unsavedModal.hide();
const saveBtn = gridRow.querySelector(".save-btn");
if (!saveBtn) return;
const observer = new MutationObserver(() => {
if (!gridRow.querySelector(".cell-changed")) {
observer.disconnect();
startExportConfirmFlow(iddatadb, btn);
}
});
observer.observe(gridRow, {
subtree: true,
attributes: true,
attributeFilter: ["class"],
});
saveBtn.click();
}, { once: true });
return;
}
// No unsaved changes — go straight to export confirm
startExportConfirmFlow(iddatadb, btn);
});
});
});
+390
View File
@@ -0,0 +1,390 @@
<?php
require_once "class/VisualLimsApiClient.class.php";
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
header("Content-Type: application/json");
// 🔹 Configura directory log (creala se non esiste)
$logDir = __DIR__ . '/logs/api/';
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
$uploadDir = realpath(__DIR__ . '/../photostrf') . '/';
// 🔹 Base URL API
$apiBaseUrl = 'https://93.43.5.102/limsapi/api/odata/';
// 🔹 Funzione per validare e convertire date
function validateDate($value)
{
// Prova a validare come data (accetta formati comuni)
$date = DateTime::createFromFormat('Y-m-d', $value) ?: DateTime::createFromFormat('Y-m-d H:i:s', $value);
if ($date) {
return $date->format('Y-m-d\TH:i:sP'); // Formato ISO 8601
}
return null; // Imposta null se non è una data valida
}
try {
$iddatadb = $_POST['iddatadb'] ?? null;
if (!$iddatadb) {
throw new Exception("Missing iddatadb");
}
// 🔹 STEP 1+2: Fetch Cliente ID from datadb and Schema ID from excel_templates
// Also fetch fixed fields stored in datadb
$stmt = $pdo->prepare("
SELECT d.idclient AS clienteId, et.idschema AS schemaId,
d.cliente_responsabile_id,
d.moltiplicatore_prezzo_id,
d.anagrafica_certest_object_id,
d.anagrafica_certest_service_id,
d.cliente_fornitore_id,
d.consegna_richiesta
FROM datadb as d
INNER JOIN excel_templates as et ON d.templateid = et.id
WHERE d.iddatadb = :iddatadb
LIMIT 1
");
$stmt->execute(['iddatadb' => $iddatadb]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$result) {
throw new Exception("No Cliente/Schema found for iddatadb {$iddatadb}");
}
$clienteId = (int) $result['clienteId'];
$schemaId = (int) $result['schemaId'];
// Extract fixed fields (nullable INTs)
$clienteResponsabile = !empty($result['cliente_responsabile_id']) ? (int) $result['cliente_responsabile_id'] : null;
$moltiplicatorePrezzo = !empty($result['moltiplicatore_prezzo_id']) ? (int) $result['moltiplicatore_prezzo_id'] : null;
$anagraficaObject = !empty($result['anagrafica_certest_object_id']) ? (int) $result['anagrafica_certest_object_id'] : null;
$anagraficaService = !empty($result['anagrafica_certest_service_id'])? (int) $result['anagrafica_certest_service_id']: null;
$clienteFornitore = !empty($result['cliente_fornitore_id'])? (int) $result['cliente_fornitore_id']: null;
$consegnaRichiesta = !empty($result['consegna_richiesta']) ? $result['consegna_richiesta'] : null;
// 🔹 STEP 3: Fetch Parts (including idmatrice)
$stmt = $pdo->prepare("
SELECT part_number, part_description, material, color, mix, idmatrice
FROM identification_parts
WHERE iddatadb = :iddatadb
");
$stmt->execute(['iddatadb' => $iddatadb]);
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 🔹 STEP 4: Fetch Field Values with Labels
$stmt = $pdo->prepare("
SELECT
idd.field_value,
m.field_label,
m.schema_id,
m.field_id
FROM
import_data_details as idd
JOIN template_mapping m ON idd.mapping_id = m.id
WHERE idd.id = :iddatadb
");
$stmt->execute(['iddatadb' => $iddatadb]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$fieldValues = [];
$valueMap = [];
foreach ($rows as $row) {
$fieldValues[] = [
"IdCommesseCustomFields" => (int) $row['field_id'],
"Valore" => $row['field_value'],
"FieldLabel" => $row['field_label']
];
$valueMap[(int) $row['field_id']] = $row['field_value'];
}
// Logga i fieldValues in error_log
$logFieldValues = "FieldValues dal DB (iddatadb={$iddatadb}):\n" . json_encode($fieldValues, JSON_PRETTY_PRINT);
error_log($logFieldValues);
// 🔹 Initialize API client
$api = VisualLimsApiClient::getInstance();
// 🔹 STEP 5: Create CommessaWeb
// Fixed fields are sent as direct properties — they are navigation properties on Commessa
// accepted by the XAF API even though not explicitly listed in OData $metadata
$commessaWebPayload = [
"Cliente" => $clienteId,
"SchemaCustomField" => $schemaId,
"Richiedente" => "Test Web Import", // TODO: replace with real value
"Descrizione" => "TEST CommessaWeb", // TODO: replace with real value
"CustomerManager" => $clienteResponsabile,
"PriceMultiplier" => $moltiplicatorePrezzo,
"CertestObjectMasterData" => $anagraficaObject,
"CertestServiceMasterData" => $anagraficaService,
"CustomerSupplier" => $clienteFornitore, // PLACEHOLDER — to be implemented
// DeliveryRequest goes to Campione, not CommessaWeb
];
// Costruisci log curl-like per STEP 5
$jsonPayload = json_encode($commessaWebPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep5 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'";
$commessaWeb = $api->post("CommessaWeb", $commessaWebPayload);
$logContentStep5 .= "\n\nRESPONSE:\n" . json_encode($commessaWeb, JSON_PRETTY_PRINT);
// Salva log
$logFileStep5 = $logDir . "commessa_create_step5_" . $iddatadb . "_" . time() . ".txt";
file_put_contents($logFileStep5, $logContentStep5);
$commessaId = $commessaWeb["IdCommessa"];
$commessaWebCode = substr($commessaWeb["CodiceCommessa"] ?? "TEST CommessaWeb", 0, 30); // Limite a 30 caratteri
// 🔹 STEP 6: Create Campioni (Samples) for each part
$campioni = [];
$logContentStep6 = "";
foreach ($parts as $index => $part) {
$matriceId = (int) ($part["idmatrice"] ?? 0);
if ($matriceId <= 0) {
throw new Exception("Invalid or missing idmatrice for part: " . ($part["part_number"] ?? "Unknown"));
}
$campionePayload = [
"Commessa" => $commessaId,
"Matrice" => $matriceId,
"SottoMatrice" => null,
"SchemaCustomField" => $schemaId,
"NoteWeb" => $part["part_description"] ?? "",
"DeliveryRequest" => $consegnaRichiesta,
];
// Costruisci curl-like per questo campione
$jsonPayload = json_encode($campionePayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep6 .= "CAMPIONE #{$index}\n" .
"curl --location --request POST '{$apiBaseUrl}Campione' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'\n\n";
$campione = $api->post("Campione", $campionePayload);
$logContentStep6 .= "RESPONSE:\n" . json_encode($campione, JSON_PRETTY_PRINT) . "\n\n---\n";
$campione["PartNumber"] = $part["part_number"] ?? "";
$campione["Material"] = $part["material"] ?? "";
$campione["Color"] = $part["color"] ?? "";
$campione["Mix"] = $part["mix"] ?? "";
$campioni[] = $campione;
}
// Salva log per STEP 6
$logFileStep6 = $logDir . "commessa_{$commessaId}_campioni_step6_" . time() . ".txt";
file_put_contents($logFileStep6, $logContentStep6);
// 🔹 STEP 6.1: Fetch photos linked to this iddatadb
$stmtPhotos = $pdo->prepare("
SELECT id, file_path, file_name
FROM datadb_photos
WHERE iddatadb = :iddatadb
ORDER BY id ASC
");
$stmtPhotos->execute(['iddatadb' => $iddatadb]);
$photos = $stmtPhotos->fetchAll(PDO::FETCH_ASSOC);
// 🔹 STEP 6.2: Upload photos to the first (main) Campione only
$photosUploaded = 0;
$logContentPhotos = "Photos for CommessaWeb {$commessaId} (iddatadb={$iddatadb}):\n";
$logContentPhotos .= "Total photos found: " . count($photos) . ", campioni: " . count($campioni) . "\n\n";
if (!empty($campioni) && !empty($photos)) {
$mainCampione = $campioni[0];
$campioneId = (int)($mainCampione['IdCampione'] ?? 0);
if ($campioneId > 0) {
$logContentPhotos .= "=== Campione {$campioneId} (main) ===\n";
foreach ($photos as $photo) {
$photoPath = $uploadDir . '/' . ltrim($photo['file_path'], './');
$fullPath = realpath($photoPath);
if (!$fullPath || !file_exists($fullPath)) {
$logContentPhotos .= "SKIP (file not found): {$photoPath}\n";
continue;
}
$photoEndpoint = "Campione({$campioneId})/UploadCampioneFile";
$logContentPhotos .= "curl --location --request POST '{$apiBaseUrl}{$photoEndpoint}' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--form 'file=@{$fullPath}'\n\n";
$photoResult = $api->postMultipart($photoEndpoint, $fullPath, $photo['file_name']);
$logContentPhotos .= "RESPONSE:\n" . json_encode($photoResult, JSON_PRETTY_PRINT) . "\n\n---\n";
$photosUploaded++;
}
} else {
$logContentPhotos .= "SKIP: main campione has invalid IdCampione\n";
}
} elseif (empty($campioni)) {
$logContentPhotos .= "SKIP: no campioni created, cannot upload photos\n";
}
$logFilePhotos = $logDir . "commessa_{$commessaId}_photos_step5_2_" . time() . ".txt";
file_put_contents($logFilePhotos, $logContentPhotos);
// 🔹 STEP 7: Update Custom Fields for CommessaWeb
if (!empty($fieldValues)) {
// GET con espansione per CustomField
$expand = "CommesseCustomFields(\$expand=CustomField)";
$commessaWithFields = $api->get("CommessaWeb({$commessaId})?\$expand={$expand}");
// Logga il GET
$logContentGet = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
"--header 'Authorization: Bearer ••••••'\n\n" .
"RESPONSE:\n" . json_encode($commessaWithFields, JSON_PRETTY_PRINT);
$logFileGet = $logDir . "commessa_{$commessaId}_get_step7_" . time() . ".txt";
file_put_contents($logFileGet, $logContentGet);
// Prepara payload PATCH
$commessaCustomFields = [];
foreach ($commessaWithFields["CommesseCustomFields"] as $customField) {
$definitionId = (int) ($customField["CustomField"]["IdCustomField"] ?? 0);
$fieldId = (int) $customField["IdCommesseCustomFields"];
$currentValue = $customField["Valore"] ?? '';
$fieldType = $customField["CustomField"]["Tipo"] ?? '';
$newValue = isset($valueMap[$definitionId]) ? $valueMap[$definitionId] : $currentValue;
// Valida se il campo è di tipo Data
if ($fieldType === 'Data' && $newValue !== $currentValue) {
$newValue = validateDate($newValue);
}
$commessaCustomFields[] = [
"IdCommesseCustomFields" => $fieldId,
"Valore" => $newValue
];
}
$logFileStep7 = null;
if (!empty($commessaCustomFields)) {
$updatePayload = ["CommesseCustomFields" => $commessaCustomFields];
// Logga payload e response
$jsonPayload = json_encode($updatePayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$logContentStep7 = "curl --location --request PATCH '{$apiBaseUrl}CommessaWeb({$commessaId})' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{$jsonPayload}'";
$patchResponse = $api->patch("CommessaWeb({$commessaId})", $updatePayload);
$logContentStep7 .= "\n\nRESPONSE:\n" . json_encode($patchResponse, JSON_PRETTY_PRINT);
$logFileStep7 = $logDir . "commessa_{$commessaId}_update_step7_" . time() . ".txt";
file_put_contents($logFileStep7, $logContentStep7);
}
}
// 🔹 STEP 8: Update datadb with idcommessaweb, commessaweb, and status
$stmt = $pdo->prepare("
UPDATE datadb
SET idcommessaweb = :idcommessaweb, commessaweb = :commessaweb, status = 'l'
WHERE iddatadb = :iddatadb
");
$stmt->execute([
'idcommessaweb' => $commessaId,
'commessaweb' => $commessaWebCode,
'iddatadb' => $iddatadb
]);
// 🔹 STEP 9: Send CommessaWeb to laboratory (commentato come richiesto)
/*
$sendResult = $api->post("CommessaWeb({$commessaId})/InviaCommessa", []);
// Logga il POST
$logContentStep9 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/InviaCommessa' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{}'\n\n" .
"RESPONSE:\n" . json_encode($sendResult, JSON_PRETTY_PRINT);
$logFileStep9 = $logDir . "commessa_{$commessaId}_send_step9_" . time() . ".txt";
file_put_contents($logFileStep9, $logContentStep9);
*/
// 🔹 STEP 9.5: Importazione da CommessaWeb a Commessa (commentato come richiesto)
// Supplier call: POST api/odata/CommessaWeb(XXX)/ImportaCommessa
$importResult = $api->post("CommessaWeb({$commessaId})/ImportaCommessa", []);
// Logga il POST
$logContentStep91 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/ImportaCommessa' \\\n" .
"--header 'Content-Type: application/json' \\\n" .
"--header 'Authorization: Bearer ••••••' \\\n" .
"--data '{}'\n\n" .
"RESPONSE:\n" . json_encode($importResult, JSON_PRETTY_PRINT);
$logFileStep91 = $logDir . "commessa_{$commessaId}_importa_step91_" . time() . ".txt";
file_put_contents($logFileStep91, $logContentStep91);
// 🔹 STEP 10: GET di controllo post-PATCH
$expand = "CommesseCustomFields(\$expand=CustomField)";
$commessaAfterPatch = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand);
// Logga il GET di controllo
$logContentStep10 = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
"--header 'Authorization: Bearer ••••••'\n\n" .
"RESPONSE:\n" . json_encode($commessaAfterPatch, JSON_PRETTY_PRINT);
$logFileStep10 = $logDir . "commessa_{$commessaId}_get_step10_" . time() . ".txt";
file_put_contents($logFileStep10, $logContentStep10);
// 🔹 STEP 11: Prepare final response
$finalCommessa = [
"Cliente" => $clienteId,
"SchemaCustomField" => $schemaId,
"Richiedente" => $commessaWeb["Richiedente"] ?? "Web Import",
"Descrizione" => $commessaWeb["Descrizione"] ?? "",
"CommesseCustomFields" => $commessaAfterPatch["CommesseCustomFields"] ?? [],
"Campioni" => $campioni,
"Inviata" => 0 // Non inviato, come richiesto
];
echo json_encode([
"success" => true,
"idcommessaweb" => $commessaId,
"commessaweb" => $commessaWebCode,
"commessaWeb" => $finalCommessa,
"commessaWebApiResponse" => $commessaWeb, // Incluso per debug
"totalCampioni" => count($campioni),
"totalCustomFields" => count($commessaAfterPatch["CommesseCustomFields"] ?? []),
"totalPhotos" => count($photos),
"message" => "Export successful",
"logFiles" => [
"step5_create" => $logFileStep5,
"step5_2_photos" => $logFilePhotos,
"step6_campioni" => $logFileStep6,
"step7_patch" => $logFileStep7 ?? null,
"step9_1_importa" => $logFileStep91,
"step10_get" => $logFileStep10
]
]);
} catch (Exception $e) {
error_log("LIMS Export Error: " . $e->getMessage() . "\nTrace: " . $e->getTraceAsString());
echo json_encode([
"success" => false,
"message" => "Export failed: " . $e->getMessage(),
"logFiles" => [
"step5_create" => $logFileStep5 ?? null,
"step5_2_photos" => $logFilePhotos ?? null,
"step6_campioni" => $logFileStep6 ?? null,
"step7_patch" => $logFileStep7 ?? null,
"step9_1_importa" => $logFileStep91 ?? null,
"step10_get" => $logFileStep10 ?? null
]
]);
}
@@ -0,0 +1,40 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
// Endpoint: GET api/odata/AnagraficaCertestObject
$endpoint = 'AnagraficaCertestObject';
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
$options = []; // es: ['$top' => 100]
// Debug: salva URL usata
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
$query = http_build_query($options);
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
// Chiamata API
$data = $api->get($endpoint, $options);
// Salva il JSON in locale
file_put_contents(__DIR__ . '/anagrafica_certest_object_response.json', json_encode($data, JSON_PRETTY_PRINT));
echo json_encode($data);
} catch (Exception $e) {
file_put_contents(
__DIR__ . '/error_log.txt',
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
@@ -0,0 +1,40 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
// Endpoint: GET api/odata/AnagraficaCertestService
$endpoint = 'AnagraficaCertestService';
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
$options = []; // es: ['$top' => 100]
// Debug: salva URL usata
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
$query = http_build_query($options);
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
// Chiamata API
$data = $api->get($endpoint, $options);
// Salva il JSON in locale
file_put_contents(__DIR__ . '/anagrafica_certest_service_response.json', json_encode($data, JSON_PRETTY_PRINT));
echo json_encode($data);
} catch (Exception $e) {
file_put_contents(
__DIR__ . '/error_log.txt',
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
@@ -0,0 +1,40 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$idCliente = isset($_GET['id_cliente']) ? (int)$_GET['id_cliente'] : 0;
if ($idCliente <= 0) {
http_response_code(400);
echo json_encode(['error' => 'Missing or invalid id_cliente']);
exit;
}
$api = VisualLimsApiClient::getInstance();
// Build endpoint with OData $expand WITHOUT encoding '$' as %24
$endpoint = "Cliente($idCliente)?\$expand=Responsabili";
// Debug URL (real final URL)
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
$full_url = $base_url . $endpoint;
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
// Call API: options must be empty because expand is already in endpoint
$data = $api->get($endpoint, []);
file_put_contents(__DIR__ . '/cliente_responsabili_response.json', json_encode($data, JSON_PRETTY_PRINT));
// Return only the list (standard shape used by the frontend)
$responsabili = $data['Responsabili'] ?? [];
echo json_encode(['value' => $responsabili]);
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
+77 -10
View File
@@ -1,24 +1,91 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Torna al livello di public per trovare vendor/
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
// Disabilita la visualizzazione degli errori PHP per evitare output HTML
// Disable PHP error display
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
$data = $api->get("Cliente"); // Recupera i clienti
$api = VisualLimsApiClient::getInstance(); // also loads dotenv
// Salva la risposta in un file per debug
file_put_contents(__DIR__ . '/clienti_response.json', json_encode($data));
// In simulate mode: return fake clients built from idclient values already in datadb.
// This ensures client dropdowns auto-select the correct row idclient, which in turn
// triggers the ClienteResponsabile select to populate via the mock.
if (($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true') {
require_once __DIR__ . '/class/db-functions.php';
$pdo = DBHandlerSelect::getInstance()->getConnection();
$stmt = $pdo->query("SELECT DISTINCT idclient FROM datadb WHERE idclient IS NOT NULL AND idclient > 0 ORDER BY idclient ASC");
$ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
$fakeClients = array_map(fn($id) => [
'IdCliente' => (int) $id,
'Nominativo' => "Cliente Simulato {$id}",
'CodiceCliente' => "SIM_{$id}",
], $ids);
echo json_encode(['value' => $fakeClients]);
exit;
}
// Parametri OData
$params = [
'$select' => 'IdCliente,Nominativo,CodiceCliente',
'$orderby' => 'Nominativo asc'
];
// Costruisce query string con encoding corretto
$queryString = http_build_query($params);
// Componi endpoint finale
$endpoint = "Cliente?$queryString";
// Funzione per eseguire la chiamata con retry
function makeApiRequest($api, $endpoint, $maxRetries = 3)
{
for ($retry = 0; $retry < $maxRetries; $retry++) {
try {
// Tenta la chiamata API
$data = $api->get($endpoint);
// Salva risposta per debug
file_put_contents(__DIR__ . '/clienti_response.json', json_encode($data, JSON_PRETTY_PRINT));
return $data;
} catch (Exception $e) {
$errorMessage = $e->getMessage();
// Controlla se l'errore è legato all'autenticazione (HTTP 400 con messaggio specifico)
if (strpos($errorMessage, 'HTTP 400') !== false && strpos($errorMessage, 'Cannot persist the object') !== false) {
// Forza il refresh del token
try {
// Assumi che VisualLimsApiClient abbia un metodo per il refresh del token
$api->refreshToken(); // Da implementare in VisualLimsApiClient se non esiste
error_log("Tentativo $retry: Refresh token eseguito per endpoint $endpoint");
} catch (Exception $refreshEx) {
error_log("Errore durante il refresh del token: " . $refreshEx->getMessage());
throw new Exception("Impossibile eseguire il refresh del token: " . $refreshEx->getMessage());
}
// Ritarda leggermente prima del retry
usleep(500000); // 500ms
continue;
}
// Altri errori non gestiti dal retry
throw $e;
}
}
throw new Exception("Massimo numero di tentativi raggiunto per $endpoint");
}
// Esegui la chiamata con retry
$data = makeApiRequest($api, $endpoint);
echo json_encode($data);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'error' => $e->getMessage()
]);
$errorResponse = [
'error' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
];
error_log("Errore in get_clienti.php: " . json_encode($errorResponse));
echo json_encode($errorResponse);
}
+39
View File
@@ -0,0 +1,39 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
// ID della CommessaWeb specifica (cambialo di volta in volta)
$id = 529435; // TODO: Cambia questo valore con l'ID desiderato
// Endpoint per recuperare la CommessaWeb specifica con espansione dello schema custom
$endpoint = "CommessaWeb({$id})";
// Opzioni per l'espansione: includi OrderCustomFields per ottenere i campi custom dello schema assegnato all'ordine
$options = ['$expand' => 'OrderCustomFields'];
// 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 JSON in locale
file_put_contents(__DIR__ . '/commessaweb_schema_response.json', json_encode($data, JSON_PRETTY_PRINT));
echo json_encode($data);
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
+21 -11
View File
@@ -1,5 +1,5 @@
<?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';
header('Content-Type: application/json');
@@ -9,20 +9,30 @@ error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
// ID del campo custom passato da GET oppure default
$customFieldId = isset($_GET['field_id']) && is_numeric($_GET['field_id']) ? intval($_GET['field_id']) : 156;
// მივიღოთ მრავლობითი field_ids
$fieldIds = [];
if (isset($_GET['field_ids'])) {
$fieldIds = array_filter(array_map('intval', explode(',', $_GET['field_ids'])));
}
// Endpoint con $expand per ottenere i valori
$endpoint = "CustomField($customFieldId)?\$expand=CustomFieldsValues";
// თუ არ გადმოგვცეს -> ერთი default
if (empty($fieldIds)) {
$fieldIds = [156];
}
// Recupera i dati dal server
$data = $api->get($endpoint);
$results = [];
// Salva la risposta in un file per debug
file_put_contents(__DIR__ . '/customfield_values_response.json', json_encode($data));
foreach ($fieldIds as $customFieldId) {
$endpoint = "CustomField($customFieldId)?\$expand=CustomFieldsValues";
$data = $api->get($endpoint);
// Output JSON al client
echo json_encode($data);
$results[$customFieldId] = $data['CustomFieldsValues'] ?? [];
}
// Debug ფაილი
file_put_contents(__DIR__ . '/customfield_values_response.json', json_encode($results));
echo json_encode($results);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
+93
View File
@@ -0,0 +1,93 @@
<?php
// get_fixed_field_data.php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
$field = $_GET['field'] ?? ''; // es: MoltiplicatorePrezzo, AnagraficaCertestObject, ...
if (!$field) {
http_response_code(400);
echo json_encode(['error' => 'Parametro "field" mancante']);
exit;
}
$api = VisualLimsApiClient::getInstance(); // also loads dotenv as a side-effect
$simulate = ($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true';
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
$data = null;
$endpoint = null;
$cache_file = null;
$options = []; // qui puoi aggiungere filtri/ordering per campo se serve
try {
switch ($field) {
case 'MoltiplicatorePrezzo':
$endpoint = 'MoltiplicatorePrezzi';
$cache_file = __DIR__ . '/cache/moltiplicatori_prezzo.json';
break;
case 'AnagraficaCertestObject':
$endpoint = 'AnagraficaCertestObject';
$cache_file = __DIR__ . '/cache/anagrafica_certest_object.json';
break;
case 'AnagraficaCertestService':
$endpoint = 'AnagraficaCertestService';
$cache_file = __DIR__ . '/cache/anagrafica_certest_service.json';
break;
case 'ClienteResponsabile':
$id_cliente = (int)($_GET['id_cliente'] ?? 0);
if ($id_cliente <= 0) {
if (!$simulate) {
http_response_code(400);
echo json_encode(['error' => 'Manca o invalido id_cliente']);
exit;
}
$id_cliente = 1; // dummy — mock ignores the actual ID
}
$endpoint = "Cliente($id_cliente)?\$expand=Responsabili";
$cache_file = __DIR__ . '/cache/cliente_responsabili_' . $id_cliente . '.json';
break;
// case 'FuturoCampo5':
// $endpoint = 'QualcosaElse';
// break;
default:
http_response_code(400);
echo json_encode(['error' => "Campo non supportato: $field"]);
exit;
}
// Caching skipped in simulate mode to avoid polluting real-data cache files
if (!$simulate && $cache_file && file_exists($cache_file) && (time() - filemtime($cache_file) < 3600)) { // 1 ora
$data = json_decode(file_get_contents($cache_file), true);
} else {
$data = $api->get($endpoint, $options);
if (!$simulate && $cache_file) {
file_put_contents($cache_file, json_encode($data, JSON_PRETTY_PRINT));
}
}
// Log ultimo URL (opzionale, per debug)
$full_url = $base_url . $endpoint . ($options ? '?' . http_build_query($options) : '');
file_put_contents(__DIR__ . '/last_urls.log', date('c') . " - $field - $full_url\n", FILE_APPEND);
echo json_encode($data);
} catch (Exception $e) {
file_put_contents(
__DIR__ . '/error_log.txt',
date('Y-m-d H:i:s') . " [$field] " . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
+59
View File
@@ -0,0 +1,59 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Risale a root/vendor/
use Dotenv\Dotenv;
// Set JSON header
header('Content-Type: application/json');
// Debug: Log the path where we expect the .env file
$envPath = dirname(__DIR__, 2);
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Expected .env path: ' . $envPath . PHP_EOL, FILE_APPEND);
// Carica il file .env dalla root del progetto
try {
$dotenv = Dotenv::createImmutable($envPath);
$dotenv->load();
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore caricamento .env: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore caricamento configurazione: ' . $e->getMessage()]);
exit(1);
}
// Recupera le variabili d'ambiente
$dbHost = $_ENV['DB_HOST'];
$dbName = $_ENV['DB_DATABASE'];
$dbUser = $_ENV['DB_USERNAME'];
$dbPass = $_ENV['DB_PASSWORD'];
$dbPrefix = $_ENV['DB_PREFIX'];
// Debug: Log database connection details (excluding password)
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . " - DB Connection: host=$dbHost, dbname=$dbName, user=$dbUser, prefix=$dbPrefix" . PHP_EOL, FILE_APPEND);
// Connessione al database MySQL
try {
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore connessione DB: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore connessione al database: ' . $e->getMessage()]);
exit(1);
}
try {
// Query per recuperare i valori distinti di MacroMatrice, escludendo quelli che iniziano con '*' e ordinandoli
$query = "SELECT DISTINCT MacroMatrice FROM {$dbPrefix}matrici WHERE MacroMatrice IS NOT NULL AND MacroMatrice NOT LIKE '*%' ORDER BY MacroMatrice ASC";
$stmt = $pdo->prepare($query);
$stmt->execute();
$macroMatrici = $stmt->fetchAll(PDO::FETCH_COLUMN);
// Debug: Log del numero di MacroMatrice recuperate
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Retrieved ' . count($macroMatrici) . ' MacroMatrice from database' . PHP_EOL, FILE_APPEND);
// Restituisci risposta JSON
echo json_encode(['success' => true, 'value' => $macroMatrici]);
} catch (PDOException $e) {
// Log errore e restituisci risposta di errore
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore nel recupero delle MacroMatrice: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore nel recupero delle MacroMatrice: ' . $e->getMessage()]);
exit(1);
}
+36
View File
@@ -0,0 +1,36 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
// Endpoint per recuperare le Matrici
$endpoint = 'Matrice';
// (Opzionale) aggiungi parametri, ad esempio $top per limitare i risultati
$options = []; // oppure ad esempio: ['$top' => 100]
// 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 JSON in locale
file_put_contents(__DIR__ . '/matrici_response.json', json_encode($data, JSON_PRETTY_PRINT));
echo json_encode($data);
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
+59
View File
@@ -0,0 +1,59 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Risale a root/vendor/
use Dotenv\Dotenv;
// Set JSON header
header('Content-Type: application/json');
// Debug: Log the path where we expect the .env file
$envPath = dirname(__DIR__, 2);
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Expected .env path: ' . $envPath . PHP_EOL, FILE_APPEND);
// Carica il file .env dalla root del progetto
try {
$dotenv = Dotenv::createImmutable($envPath);
$dotenv->load();
} catch (Exception $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore caricamento .env: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore caricamento configurazione: ' . $e->getMessage()]);
exit(1);
}
// Recupera le variabili d'ambiente
$dbHost = $_ENV['DB_HOST'];
$dbName = $_ENV['DB_DATABASE'];
$dbUser = $_ENV['DB_USERNAME'];
$dbPass = $_ENV['DB_PASSWORD'];
$dbPrefix = $_ENV['DB_PREFIX'];
// Debug: Log database connection details (excluding password)
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . " - DB Connection: host=$dbHost, dbname=$dbName, user=$dbUser, prefix=$dbPrefix" . PHP_EOL, FILE_APPEND);
// Connessione al database MySQL
try {
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUser, $dbPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore connessione DB: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore connessione al database: ' . $e->getMessage()]);
exit(1);
}
try {
// Query per recuperare le matrici, includendo MacroMatrice, escludendo quelle che iniziano con '*' e ordinandole
$query = "SELECT IdMatrice, NomeMatrice, MacroMatrice FROM {$dbPrefix}matrici WHERE NomeMatrice NOT LIKE '*%' ORDER BY NomeMatrice ASC";
$stmt = $pdo->prepare($query);
$stmt->execute();
$matrici = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Debug: Log del numero di matrici recuperate
file_put_contents(__DIR__ . '/debug_log.txt', date('Y-m-d H:i:s') . ' - Retrieved ' . count($matrici) . ' matrices from database' . PHP_EOL, FILE_APPEND);
// Restituisci risposta JSON
echo json_encode(['success' => true, 'value' => $matrici]);
} catch (PDOException $e) {
// Log errore e restituisci risposta di errore
file_put_contents(__DIR__ . '/error_log.txt', date('Y-m-d H:i:s') . ' - Errore nel recupero delle matrici: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
echo json_encode(['success' => false, 'message' => 'Errore nel recupero delle matrici: ' . $e->getMessage()]);
exit(1);
}
+37
View File
@@ -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>';
}
@@ -0,0 +1,55 @@
<?php
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
header('Content-Type: application/json');
ini_set('display_errors', '0');
error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
// Endpoint per recuperare i Moltiplicatori Prezzo
// (dal documento: GET api/odata/MoltiplicatorePrezzi)
$endpoint = 'MoltiplicatorePrezzi';
// Opzionale: parametri OData ($top, $filter, $orderby, ecc.)
$options = [
'$orderby' => 'Descrizione asc'
];
// Debug: salva URL usata
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
$queryParts = [];
foreach ($options as $k => $v) {
// mantieni il $ nella chiave, encoda solo il valore
$queryParts[] = $k . '=' . rawurlencode($v);
}
$query = implode('&', $queryParts);
$full_url = $base_url . $endpoint . ($query ? '?' . $query : '');
file_put_contents(__DIR__ . '/last_url.txt', $full_url . PHP_EOL, FILE_APPEND);
// Chiamata API
$data = $api->get($endpoint, $options);
// ✅ Force sort locally by "Descrizione" (A→Z)
if (isset($data['value']) && is_array($data['value'])) {
usort($data['value'], function ($a, $b) {
$da = isset($a['Descrizione']) ? trim((string)$a['Descrizione']) : '';
$db = isset($b['Descrizione']) ? trim((string)$b['Descrizione']) : '';
return strcasecmp($da, $db); // case-insensitive alphabetical
});
}
// Salva il JSON in locale
file_put_contents(__DIR__ . '/moltiplicatori_prezzo_response.json', json_encode($data, JSON_PRETTY_PRINT));
echo json_encode($data);
} catch (Exception $e) {
file_put_contents(
__DIR__ . '/error_log.txt',
date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
+1 -1
View File
@@ -9,7 +9,7 @@ error_reporting(E_ALL);
try {
$api = VisualLimsApiClient::getInstance();
$rapporto_id = 515081;
$rapporto_id = 533329;
// Costruzione manuale dell'endpoint con espansione annidata
$endpoint = "Rapporto($rapporto_id)?\$expand=CampioniDatiRapporto(\$expand=AnalisiDatiRapporto,CustomFieldsDatiRapporto)";
+286 -133
View File
@@ -59,7 +59,8 @@ foreach ($allMappings as $mapping) {
}
}
if (!$mainFieldMapping) {
$mainFieldMapping = reset(array_filter($allMappings, fn($m) => !$m['is_manual']));
$filtered = array_filter($allMappings, fn($m) => !$m['is_manual']);
$mainFieldMapping = reset($filtered);
}
// Retrieve data from datadb
@@ -499,6 +500,22 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
.proceed-btn {
margin-top: 20px;
}
.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: 50px;
box-sizing: border-box;
}
</style>
<title>Dati Storici - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head>
@@ -610,142 +627,209 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
</div>
<div id="noResults" class="text-danger" style="display:none;">Nessun risultato trovato</div>
<div class="scrollbar-container"></div>
<form id="editForm">
<div class="grid-container">
<?php $fixedColumns = ['filename_import', 'status', 'importdate']; ?>
<?php if ($status === 'i'): ?>
<div class="grid-top">
<div class="grid-cell" style="flex: 0 0 100px;"></div>
<div class="grid-cell" style="flex: 0 0 100px;"></div>
<div class="grid-cell" style="flex: 0 0 100px;"></div>
<div class="grid-cell" style="flex: 0 0 150px;"></div>
<?php
foreach ($fixedColumns as $col) {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
$autoIndex = 0;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual']) {
$inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
if ($mapping['data_type'] === 'SceltaMultipla') {
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
echo "</div>";
} else {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
$autoIndex++;
<div class="grid-top">
<div class="grid-cell actions-cell" style="flex: 0 0 200px;"></div>
<?php
// Campo con main_field = 1
if ($mainFieldMapping) {
$inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
$index = $mainFieldMapping['is_manual'] ? "manual_0" : "auto_0";
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mainFieldMapping['data_type'] === 'SceltaMultipla') {
$fieldValue = $mainFieldMapping['manual_default'] ?? '';
echo "<select class='custom-field dropdown-select $inputClass' data-column='$index' data-field-id='{$mainFieldMapping['field_id']}' data-selected-value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='$index' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} else {
$fieldValue = $mainFieldMapping['manual_default'] ?? '';
if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
if ($mainFieldMapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='$index' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} elseif ($mainFieldMapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='$index' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='$index' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
}
echo "<button type='button' class='propagate-btn' data-column='$index' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
}
$manualIndex = 0;
foreach ($allMappings as $mapping) {
if ($mapping['is_manual']) {
echo "</div>";
} else {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
// Status (subito dopo main_field)
$fixedColumnsReduced = ['status'];
foreach ($fixedColumnsReduced as $col) {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
// Campi automatici (escluso main_field)
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
$inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
$fieldValue = $mapping['manual_default'] ?? '';
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
$inputClass = 'manual-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
}
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
echo "</div>";
$manualIndex++;
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} else {
echo "<div style='height: 34px;'></div>";
}
echo "</div>";
$autoIndex++;
}
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>";
?>
</div>
<?php endif; ?>
}
// Campi manuali (escluso main_field)
$manualIndex = ($mainFieldMapping && $mainFieldMapping['is_manual']) ? 1 : 0;
foreach ($allMappings as $mapping) {
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
$fieldValue = $mapping['manual_default'] ?? '';
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
$inputClass = 'manual-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
}
echo "</div>";
$manualIndex++;
}
}
// Colonne Import Reference Code, filename_import
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // Import Reference Code
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // filename_import
// AWB Number e Tracking Info
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>";
?>
</div>
<div class="grid-row">
<div class="grid-header" style="flex: 0 0 100px;">Save</div>
<div class="grid-header" style="flex: 0 0 100px;">Photos</div>
<div class="grid-header" style="flex: 0 0 100px;">Parts</div>
<div class="grid-header" data-index="3" style="flex: 0 0 150px; position: relative;">Import Reference Code<div class="resizer"></div>
<div class="grid-header actions-cell" style="flex: 0 0 200px; position: relative;">Azioni<div class="resizer"></div>
</div>
<?php
$headerIndex = 4;
foreach ($fixedColumns as $col) {
// Header per il campo main_field = 1
$headerIndex = 1;
if ($mainFieldMapping) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mainFieldMapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
// Header per status (subito dopo main_field)
foreach ($fixedColumnsReduced 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++;
}
// Header per campi automatici (escluso main_field)
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>";
$headerIndex++;
}
}
// Header per campi manuali (escluso main_field)
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>";
$headerIndex++;
}
}
// Header per Import Reference Code, filename_import
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;'>File<div class='resizer'></div></div>";
$headerIndex++;
// Header per AWB Number e Tracking Info
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>";
?>
</div>
<?php foreach ($importedData as $index => $row): ?>
<div class="grid-row" data-id="<?= $row['iddatadb'] ?>">
<div class="grid-cell" style="flex: 0 0 100px; position: relative;">
<?php if (!$is_readonly): ?>
<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>
<?php else: ?>
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; width: 100%; box-sizing: border-box;" disabled><i class="fas fa-save"></i></button>
<?php endif; ?>
</div>
<div class="grid-cell" style="flex: 0 0 100px; position: relative;">
<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>
</div>
<div class="grid-cell" style="flex: 0 0 100px; position: relative;">
<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>
<div class="grid-cell actions-cell" style="flex: 0 0 200px; position: relative;">
<div style="display: flex; gap: 5px; justify-content: center;">
<?php if (!$is_readonly): ?>
<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; flex: 1;"><i class="fas fa-save"></i></button>
<?php else: ?>
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; flex: 1;" disabled><i class="fas fa-save"></i></button>
<?php endif; ?>
<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; flex: 1;"><i class="fas fa-camera"></i></button>
<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; flex: 1;"><i class="fas fa-puzzle-piece"></i></button>
</div>
</div>
<?php
$cellIndex = 3;
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) {
$cellIndex = 1;
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
// Campo con main_field = 1
if ($mainFieldMapping) {
$detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mainFieldMapping['id']);
$detail = reset($detail) ?: ['field_value' => $mainFieldMapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mainFieldMapping['manual_default'] ?? '';
$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';
$indexField = $mainFieldMapping['is_manual'] ? "manual_0" : "auto_0";
echo "<div class='grid-cell editable-cell $requiredClass' data-col='$indexField' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
if ($mainFieldMapping['data_type'] === 'SceltaMultipla') {
echo "<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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
} elseif ($mainFieldMapping['data_type'] === 'DATE') {
echo "<input type='date' name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} elseif ($mainFieldMapping['data_type'] === 'INT') {
echo "<input type='number' name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} else {
echo "<input type='text' name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
}
echo "</div>";
$cellIndex++;
}
// Status (subito dopo main_field)
$fixedColumnsReduced = ['status'];
foreach ($fixedColumnsReduced 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') {
if ($col === 'status') {
$badgeClass = $value === 'i' ? 'status-i' : ($value === 'P' ? 'status-P' : 'status-l');
$badgeText = $value === 'i' ? 'Imported' : ($value === 'P' ? 'Progress' : 'LIMS');
// Aggiungi il numero di commessaweb se lo status è 'l'
if ($value === 'l') {
$commessaWeb = isset($row['commessaweb']) ? htmlspecialchars($row['commessaweb']) : '';
$badgeText .= " ($commessaWeb)";
}
echo "<span class='status-badge $badgeClass'>" . htmlspecialchars($badgeText) . "</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']);
$autoIndex = 0;
// Campi automatici (escluso main_field)
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
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 = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
@@ -754,7 +838,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
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;'>";
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
} elseif ($mapping['data_type'] === 'DATE') {
@@ -769,9 +853,10 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$autoIndex++;
}
}
$manualIndex = 0;
// Campi manuali (escluso main_field)
$manualIndex = ($mainFieldMapping && $mainFieldMapping['is_manual']) ? 1 : 0;
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 = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
@@ -783,7 +868,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
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;'>";
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
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' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
} elseif ($mapping['data_type'] === 'DATE') {
@@ -798,6 +883,18 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$manualIndex++;
}
}
// Colonne Import Reference Code e filename_import
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++;
echo "<div class='grid-cell' data-col='filename_import' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
echo "<a href='imported_trf/" . htmlspecialchars($row['filename_import']) . "' target='_blank'>File</a>";
echo "<input type='hidden' name='rows[$index][filename_import]' value='" . htmlspecialchars($row['filename_import']) . "'>";
echo "</div>";
$cellIndex++;
// Colonne AWB Number e Tracking Info
?>
<div class="grid-cell" style="flex: 0 0 200px;">
<select name="rows[<?= $index ?>][carrier]" class="carrier-select" <?= $is_readonly ? 'disabled' : '' ?>>
@@ -833,6 +930,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
</ul>
</nav>
</form>
<?php
if (file_exists('modal_parts.php')) {
include 'modal_parts.php';
@@ -856,6 +954,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
</div>
<?php include('jsinclude.php'); ?>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<script src="photos.js"></script>
<script src="parts.js"></script>
<script src="tracking.js"></script>
@@ -890,7 +989,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
const cells = row.querySelectorAll('td');
let match = false;
cells.forEach((cell, index) => {
if (index >= 1 && index <= 3) {
if (index >= 1 && index <= 4) { // Cerca in ID, main_field, importreferencecode, filename
const text = cell.textContent.toLowerCase();
if (text.includes(filter)) {
match = true;
@@ -934,6 +1033,18 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
}
});
});
// Gestione eliminazione multipla
const bulkActionForm = document.getElementById('bulkActionForm');
bulkActionForm.addEventListener('submit', function(e) {
const selectedCheckboxes = document.querySelectorAll('input[name="selected_ids[]"]:checked');
if (selectedCheckboxes.length === 0) {
e.preventDefault();
alert('Seleziona almeno un record da eliminare.');
} else if (!confirm('Sicuro di voler eliminare i record selezionati?')) {
e.preventDefault();
}
});
<?php else: ?>
// Gestione input e celle espandibili
const inputs = document.querySelectorAll('.cell-input');
@@ -961,8 +1072,13 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
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
@@ -977,6 +1093,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
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);
}
@@ -990,12 +1107,12 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
propagateButtons.forEach(button => {
button.addEventListener('click', function() {
if (this.hasAttribute('disabled')) return;
const columnIndex = this.getAttribute('data-column').replace('manual_', '');
const column = this.getAttribute('data-column');
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
cell.querySelector('.propagate-btn[data-column="' + column + '"]')
);
if (targetTopIndex !== -1) {
const rows = document.querySelectorAll('.grid-row');
@@ -1004,9 +1121,12 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
if (cells.length > targetTopIndex) {
const targetInput = cells[targetTopIndex].querySelector('input, select');
if (targetInput && !targetInput.hasAttribute('readonly')) {
if (targetInput.type === 'date') targetInput.value = value;
else if (targetInput.tagName === 'SELECT') targetInput.value = value;
else targetInput.value = value;
targetInput.value = value;
if (targetInput.tagName === 'SELECT') {
targetInput.setAttribute('data-selected-value', value);
const event = new Event('change');
targetInput.dispatchEvent(event);
}
}
}
});
@@ -1123,47 +1243,80 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
async function populateDropdowns() {
if (<?= json_encode($is_readonly) ?>) return;
const dropdowns = document.querySelectorAll('.dropdown-select');
if (dropdowns.length === 0) return;
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);
}
}
console.log('Dropdown trovati:', dropdowns.length);
if (dropdowns.length === 0) {
console.warn('Nessun dropdown trovato con classe .dropdown-select');
return;
}
dropdowns.forEach(dropdown => {
const fieldId = dropdown.getAttribute('data-field-id');
if (!fieldId || !dropdownData[fieldId]) {
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId);
console.log('Field IDs unici:', uniqueFieldIds);
const missingFieldIds = uniqueFieldIds.filter(fieldId => !dropdownData[fieldId]);
if (missingFieldIds.length > 0) {
try {
const response = await fetch(`get_customfield_values.php?field_ids=${missingFieldIds.join(',')}`);
if (!response.ok) {
throw new Error(`Errore HTTP: ${response.status} ${response.statusText}`);
}
const data = await response.json();
console.log('Risposta da get_customfield_values.php:', data);
if (data.error) {
console.error('Errore dal server:', data.error);
dropdowns.forEach(dropdown => {
dropdown.innerHTML = '<option value="">Errore server</option>';
});
return;
}
for (const fieldId of Object.keys(data)) {
dropdownData[fieldId] = data[fieldId] || [];
}
} catch (error) {
console.error('Errore nel fetch dei valori dei dropdown:', error);
dropdowns.forEach(dropdown => {
dropdown.innerHTML = '<option value="">Errore caricamento</option>';
});
return;
}
}
dropdowns.forEach(dropdown => {
const fieldId = dropdown.getAttribute('data-field-id');
const mappingId = dropdown.getAttribute('data-mapping-id');
const selectedValue = dropdown.getAttribute('data-selected-value') || '';
const currentValue = dropdown.value || '';
console.log(`Popolamento dropdown field_id=${fieldId}, mapping_id=${mappingId}, valore corrente=${currentValue}, valore selezionato=${selectedValue}`);
if (!fieldId || !dropdownData[fieldId]) {
dropdown.innerHTML = '<option value="">Nessun dato</option>';
return;
}
// Preserva il valore corrente o usa quello salvato
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;
// Dai priorità a data-selected-value per il caricamento iniziale
if (selectedValue === String(value.IdCustomFieldsValue)) {
option.selected = true;
} else if (currentValue === String(value.IdCustomFieldsValue)) {
option.selected = true;
}
dropdown.appendChild(option);
});
// Verifica se il valore selezionato esiste tra le opzioni
if ((selectedValue || currentValue) && dropdown.value !== (selectedValue || currentValue)) {
dropdown.value = '';
console.warn(`Valore ${selectedValue || currentValue} non trovato per fieldId ${fieldId}`);
}
});
}
populateDropdowns();
saveButtons.forEach(btn => {
btn.addEventListener('click', function() {
if (!this.hasAttribute('disabled')) {
setTimeout(populateDropdowns, 100);
}
});
});
<?php endif; ?>
});
</script>
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More