Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a626c8283e | |||
| c7416ba4a9 | |||
| 1fed113c5c | |||
| e3994d6f9f | |||
| 9af0df3cca | |||
| 48d2a3ff42 | |||
| cf44e67922 | |||
| 35021e9d9b | |||
| 497ebda65a | |||
| b0024edb70 | |||
| b9852ba226 | |||
| 407d6884a1 | |||
| 1a4beadbb2 | |||
| 4bb0445cff | |||
| 73dd8f4ce8 | |||
| bdc4e0e60c | |||
| ef8f2d8000 | |||
| 74c9a1d02a | |||
| cd3bccd183 | |||
| 78154e43a9 | |||
| 9fe9243e60 | |||
| a8330d4aba | |||
| 82d6a2ee18 | |||
| d8eddb3aa5 | |||
| f60dc64b2d | |||
| 4e4cae1df8 | |||
| 8838edf3a1 | |||
| e75be99e43 | |||
| a482d975da | |||
| 598a2cc84c | |||
| 6ec0c2062e | |||
| 5eb5bd1613 | |||
| 03771e3ca8 | |||
| 03642fdfab | |||
| f6ea17388c | |||
| 1c2b4ab7a6 | |||
| 31cb23b00e | |||
| d29563d20d | |||
| 82af925ac1 | |||
| 5d8360dd87 | |||
| 683073c244 | |||
| 8d6fe92481 | |||
| dbc66723a6 | |||
| 218fc14462 | |||
| 29e4b41874 | |||
| eef9ae8d36 | |||
| 68c867a3f4 | |||
| a9827e4e81 | |||
| b51936f784 | |||
| 15b6f38e8b | |||
| 12c6cc5f95 | |||
| a0b12463c0 | |||
| 07ddcafd3f | |||
| 7843d4b1fc | |||
| 4eae855e23 | |||
| c709f64a17 | |||
| d5f0690f59 | |||
| 6bbd3fcae9 | |||
| 9e19e9e1d4 | |||
| 7caee9c994 | |||
| f8320315f7 | |||
| 7397d86bc2 | |||
| 2deb1f101a | |||
| ed4467337f | |||
| 864714d198 | |||
| 33aacfb469 | |||
| e0e262fd32 | |||
| 5d6302fa9c | |||
| 3da8ff81c9 | |||
| a36dd02771 | |||
| 0a6fb98476 | |||
| 57ddd4bb5a | |||
| df5e6d5656 | |||
| 78495880ca | |||
| 960832efb1 | |||
| 447a0d1dea | |||
| 5b47416841 | |||
| 3e4a627ca7 | |||
| 420b0a0405 | |||
| b39d601ec9 | |||
| 89d13699b4 | |||
| 9826331545 | |||
| 9d8718d110 | |||
| 16e00f8573 | |||
| baf3f6da32 | |||
| 62bf4ebd92 | |||
| 6e465e3010 | |||
| 8b08969c69 | |||
| 25d4519684 | |||
| 34d4dc8660 | |||
| 1510ef03f1 | |||
| ce8c95921f | |||
| 095a6ae879 | |||
| 296143016a | |||
| 412dce8941 | |||
| 586226ceaf | |||
| ac09d8d0eb | |||
| 33e3ae059d | |||
| 3aa2504f3c | |||
| c1a396f246 | |||
| a45ba1c8b3 | |||
| 7a944a73f7 | |||
| 71595cc8de | |||
| f89dbd0c23 | |||
| 9ba859e15b | |||
| 672e448e9a | |||
| 0749032fbc |
@@ -1,47 +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
|
|
||||||
|
|
||||||
BASE_URL=http://localhost:8000/userarea/
|
|
||||||
+14
-7
@@ -1,16 +1,16 @@
|
|||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
APP_DEBUG=false
|
APP_DEBUG=true
|
||||||
APP_KEY=
|
APP_KEY=base64:C+sutHm6xP5sE4QXhoZFhYjArlVN11s2mDU1F8beUkM=
|
||||||
APP_URL=http://vanguard.test
|
APP_URL=http://vanguard.test
|
||||||
|
|
||||||
LOG_CHANNEL=stack
|
LOG_CHANNEL=stack
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=localhost
|
DB_HOST="localhost"
|
||||||
DB_DATABASE=vanguard
|
DB_DATABASE="xxxx"
|
||||||
DB_USERNAME=homestead
|
DB_USERNAME="xxxx"
|
||||||
DB_PASSWORD=secret
|
DB_PASSWORD="xxxxx"
|
||||||
DB_PREFIX=vg_
|
DB_PREFIX="auth_"
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
@@ -39,3 +39,10 @@ PUSHER_APP_CLUSTER=mt1
|
|||||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
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/
|
||||||
+31
-30
@@ -1,54 +1,55 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
/node_modules
|
/node_modules
|
||||||
/public/hot
|
|
||||||
/public/storage
|
|
||||||
/storage/*.key
|
|
||||||
/vendor
|
/vendor
|
||||||
|
|
||||||
/.idea
|
/.idea
|
||||||
/.fleet
|
/.fleet
|
||||||
/.vscode
|
/.vscode
|
||||||
/.vagrant
|
/.vagrant
|
||||||
Homestead.json
|
|
||||||
Homestead.yaml
|
/public/hot
|
||||||
npm-debug.log
|
/public/storage
|
||||||
yarn-error.log
|
|
||||||
.env
|
|
||||||
.phpunit.result.cache
|
|
||||||
.php_cs.cache
|
|
||||||
/documentation
|
|
||||||
/.phpunit.cache
|
|
||||||
/public/build
|
/public/build
|
||||||
|
|
||||||
|
/storage/*.key
|
||||||
|
|
||||||
|
.env
|
||||||
.env.backup
|
.env.backup
|
||||||
.env.production
|
.env.production
|
||||||
auth.json
|
auth.json
|
||||||
# File di debug e temporanei JSON e log
|
|
||||||
|
.phpunit.result.cache
|
||||||
|
.php_cs.cache
|
||||||
|
/.phpunit.cache
|
||||||
|
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
/documentation
|
||||||
|
|
||||||
|
# --- Runtime / Debug (userarea) ---
|
||||||
/public/userarea/*.json
|
/public/userarea/*.json
|
||||||
/public/userarea/*.log
|
/public/userarea/*.log
|
||||||
/public/userarea/*.txt
|
/public/userarea/*.txt
|
||||||
|
/public/userarea/*_response.json
|
||||||
# File di log nella sottocartella class
|
/public/userarea/error_log.txt
|
||||||
|
/public/userarea/import_debug.log
|
||||||
|
/public/userarea/last_url.txt
|
||||||
|
/public/userarea/logaspi/
|
||||||
|
/public/userarea/logsapi/
|
||||||
|
/public/userarea/photostrf/
|
||||||
/public/userarea/class/*.log
|
/public/userarea/class/*.log
|
||||||
|
/public/userarea/class/curl_auth_debug.log
|
||||||
|
/public/userarea/class/curl_request_debug.log
|
||||||
|
|
||||||
# File XLSX temporanei importati
|
# File XLSX temporanei importati
|
||||||
/public/userarea/imported_trf/*.xlsx
|
/public/userarea/imported_trf/*.xlsx
|
||||||
/public/userarea/xlstemplates/*.xlsx
|
/public/userarea/xlstemplates/*.xlsx
|
||||||
|
|
||||||
# Ignora cartelle di foto generate
|
# Cartelle foto generate
|
||||||
/public/photostrf/
|
/public/photostrf/
|
||||||
/public/photostrf/qrcodes/
|
/public/photostrf/qrcodes/
|
||||||
public/userarea/import_debug.log
|
|
||||||
public/userarea/last_url.txt
|
|
||||||
public/userarea/class/curl_auth_debug.log
|
|
||||||
public/userarea/class/curl_request_debug.log
|
|
||||||
public/userarea/last_url.txt
|
|
||||||
public/userarea/class/curl_auth_debug.log
|
|
||||||
public/userarea/class/curl_request_debug.log
|
|
||||||
|
|
||||||
# Ignora tutti i log
|
# Ignora tutti i log ovunque
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
|
||||||
# Ignora cartella photostrf in public/userarea
|
|
||||||
/public/userarea/photostrf/
|
|
||||||
public/userarea/customfield_values_response.json
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,21 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
\Illuminate\Database\Schema\Builder::defaultStringLength(191);
|
\Illuminate\Database\Schema\Builder::defaultStringLength(191);
|
||||||
|
|
||||||
Factory::guessFactoryNamesUsing(function (string $modelName) {
|
Factory::guessFactoryNamesUsing(function (string $modelName) {
|
||||||
return 'Database\Factories\\'.class_basename($modelName).'Factory';
|
return 'Database\Factories\\' . class_basename($modelName) . 'Factory';
|
||||||
});
|
});
|
||||||
|
|
||||||
\Illuminate\Pagination\Paginator::useBootstrap();
|
\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']
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
Verified::class => [
|
Verified::class => [
|
||||||
ActivateUser::class,
|
ActivateUser::class,
|
||||||
],
|
],
|
||||||
|
\SocialiteProviders\Manager\SocialiteWasMapped::class => [
|
||||||
|
\SocialiteProviders\Microsoft\MicrosoftExtendSocialite::class,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$app = new Illuminate\Foundation\Application(
|
$app = new Illuminate\Foundation\Application(
|
||||||
realpath(__DIR__.'/../')
|
realpath(__DIR__ . '/../')
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+2
-1
@@ -38,12 +38,13 @@
|
|||||||
"laravel/fortify": "^1.21",
|
"laravel/fortify": "^1.21",
|
||||||
"laravel/framework": "^11.0",
|
"laravel/framework": "^11.0",
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
"laravel/socialite": "^5.0",
|
"laravel/socialite": "^5.16",
|
||||||
"laravel/tinker": "^2.7",
|
"laravel/tinker": "^2.7",
|
||||||
"laravel/ui": "^4.0",
|
"laravel/ui": "^4.0",
|
||||||
"phpmailer/phpmailer": "^6.9",
|
"phpmailer/phpmailer": "^6.9",
|
||||||
"phpoffice/phpspreadsheet": "^4.1",
|
"phpoffice/phpspreadsheet": "^4.1",
|
||||||
"proengsoft/laravel-jsvalidation": "^4.0.0",
|
"proengsoft/laravel-jsvalidation": "^4.0.0",
|
||||||
|
"socialiteproviders/microsoft": "^4.7",
|
||||||
"spatie/laravel-query-builder": "^5.0",
|
"spatie/laravel-query-builder": "^5.0",
|
||||||
"vanguardapp/activity-log": "^6.0",
|
"vanguardapp/activity-log": "^6.0",
|
||||||
"vanguardapp/announcements": "^6.0",
|
"vanguardapp/announcements": "^6.0",
|
||||||
|
|||||||
Generated
+138
-13
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "ef3e05e7260284f5b7c7b4b6f93b252b",
|
"content-hash": "9c4f1e3bc3ee2180211c055e70635aef",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "akaunting/laravel-setting",
|
"name": "akaunting/laravel-setting",
|
||||||
@@ -2240,16 +2240,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/socialite",
|
"name": "laravel/socialite",
|
||||||
"version": "v5.15.1",
|
"version": "v5.16.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/socialite.git",
|
"url": "https://github.com/laravel/socialite.git",
|
||||||
"reference": "cc02625f0bd1f95dc3688eb041cce0f1e709d029"
|
"reference": "40a2dc98c53d9dc6d55eadb0d490d3d72b73f1bf"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/cc02625f0bd1f95dc3688eb041cce0f1e709d029",
|
"url": "https://api.github.com/repos/laravel/socialite/zipball/40a2dc98c53d9dc6d55eadb0d490d3d72b73f1bf",
|
||||||
"reference": "cc02625f0bd1f95dc3688eb041cce0f1e709d029",
|
"reference": "40a2dc98c53d9dc6d55eadb0d490d3d72b73f1bf",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2271,16 +2271,16 @@
|
|||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "5.x-dev"
|
|
||||||
},
|
|
||||||
"laravel": {
|
"laravel": {
|
||||||
"providers": [
|
|
||||||
"Laravel\\Socialite\\SocialiteServiceProvider"
|
|
||||||
],
|
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"Socialite": "Laravel\\Socialite\\Facades\\Socialite"
|
"Socialite": "Laravel\\Socialite\\Facades\\Socialite"
|
||||||
}
|
},
|
||||||
|
"providers": [
|
||||||
|
"Laravel\\Socialite\\SocialiteServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -2308,7 +2308,7 @@
|
|||||||
"issues": "https://github.com/laravel/socialite/issues",
|
"issues": "https://github.com/laravel/socialite/issues",
|
||||||
"source": "https://github.com/laravel/socialite"
|
"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",
|
"name": "laravel/tinker",
|
||||||
@@ -4980,6 +4980,131 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-04-27T21:32:50+00:00"
|
"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",
|
"name": "spatie/laravel-package-tools",
|
||||||
"version": "1.16.4",
|
"version": "1.16.4",
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ return [
|
|||||||
Proengsoft\JsValidation\JsValidationServiceProvider::class,
|
Proengsoft\JsValidation\JsValidationServiceProvider::class,
|
||||||
Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class,
|
Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class,
|
||||||
Laravel\Socialite\SocialiteServiceProvider::class,
|
Laravel\Socialite\SocialiteServiceProvider::class,
|
||||||
|
\SocialiteProviders\Manager\ServiceProvider::class,
|
||||||
Webpatser\Countries\CountriesServiceProvider::class,
|
Webpatser\Countries\CountriesServiceProvider::class,
|
||||||
Intervention\Image\ImageServiceProvider::class,
|
Intervention\Image\ImageServiceProvider::class,
|
||||||
Jenssegers\Agent\AgentServiceProvider::class,
|
Jenssegers\Agent\AgentServiceProvider::class,
|
||||||
|
|||||||
+3
-3
@@ -11,9 +11,9 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// 'social' => [
|
'social' => [
|
||||||
// 'providers' => ['facebook', 'twitter', 'google'],
|
'providers' => ['microsoft'],
|
||||||
// ],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|||||||
+9
-3
@@ -64,9 +64,15 @@ return [
|
|||||||
'redirect' => env('GOOGLE_CALLBACK_URI'),
|
'redirect' => env('GOOGLE_CALLBACK_URI'),
|
||||||
],
|
],
|
||||||
|
|
||||||
// 'authy' => [
|
'microsoft' => [
|
||||||
// 'key' => env('AUTHY_KEY'),
|
'client_id' => env('MICROSOFT_CLIENT_ID'),
|
||||||
// ],
|
'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
|
||||||
|
'redirect' => env('MICROSOFT_REDIRECT_URI'),
|
||||||
|
],
|
||||||
|
|
||||||
|
// 'authy' => [
|
||||||
|
// 'key' => env('AUTHY_KEY'),
|
||||||
|
// ],
|
||||||
|
|
||||||
'resend' => [
|
'resend' => [
|
||||||
'key' => env('RESEND_KEY'),
|
'key' => env('RESEND_KEY'),
|
||||||
|
|||||||
@@ -32,3 +32,4 @@ $langdatatables = [
|
|||||||
"paginate_next" => "Next",
|
"paginate_next" => "Next",
|
||||||
"paginate_previous" => "Previous"
|
"paginate_previous" => "Previous"
|
||||||
];
|
];
|
||||||
|
$quotationstitle = "Quotations";
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
@@ -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()
|
public static function getInstance()
|
||||||
{
|
{
|
||||||
if (self::$instance === null) {
|
if (self::$instance === null) {
|
||||||
self::$instance = new VisualLimsApiClient();
|
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3));
|
||||||
|
$dotenv->load();
|
||||||
|
|
||||||
|
$simulate = ($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true';
|
||||||
|
|
||||||
|
if ($simulate) {
|
||||||
|
require_once __DIR__ . '/VisualLimsApiClientMock.class.php';
|
||||||
|
self::$instance = new VisualLimsApiClientMock();
|
||||||
|
} else {
|
||||||
|
self::$instance = new VisualLimsApiClient();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function authenticate()
|
private function authenticate($retryCount = 0, $maxRetries = 3)
|
||||||
{
|
{
|
||||||
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
$ch = curl_init("{$this->baseUrl}/api/authentication/authenticate");
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
@@ -45,16 +55,22 @@ class VisualLimsApiClient
|
|||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
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);
|
curl_setopt($ch, CURLOPT_STDERR, $log);
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
$curl_error = curl_error($ch);
|
$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);
|
fclose($log);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
if ($response === false || $http_code != 200) {
|
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));
|
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;
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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: Fri, 29 Aug 2025 13:36:31 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.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NjQ4MTc5MSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.066odH6XJ_XK1D_w6xYBCXncA6Hx1AgFqsanfvKULyk]
|
|
||||||
* [HTTP/2] [1] [accept: application/json]
|
|
||||||
> GET /limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues HTTP/2
|
|
||||||
Host: 93.43.5.102
|
|
||||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1NjQ4MTc5MSwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.066odH6XJ_XK1D_w6xYBCXncA6Hx1AgFqsanfvKULyk
|
|
||||||
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: Fri, 29 Aug 2025 13:36:33 GMT
|
|
||||||
<
|
|
||||||
* Connection #0 to host 93.43.5.102 left intact
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -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
|
||||||
File diff suppressed because one or more lines are too long
@@ -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
|
||||||
Binary file not shown.
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
@@ -20,17 +20,10 @@ if (!$template) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug del JSON
|
// Recupera tutte le routine dal database
|
||||||
$clientSpecificFieldsJson = $template['client_specific_fields'] ?? '{}';
|
$stmt = $pdo->prepare("SELECT * FROM routine");
|
||||||
error_log("Raw client_specific_fields JSON: " . $clientSpecificFieldsJson);
|
$stmt->execute();
|
||||||
|
$routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$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));
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<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 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" />
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
<style>
|
<!-- Include jQuery prima di Select2 -->
|
||||||
.client-field-row .row {
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
margin-bottom: 0 !important;
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
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>
|
|
||||||
<title>Edit Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Edit Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -74,7 +48,7 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="mb-0">UpdateXLS Template</h5>
|
<h5 class="mb-0">Update XLS Template</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="mb-2">Edit the following form in order to update the selected import XLS template</p>
|
<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">
|
<ul class="mb-0">
|
||||||
<li>Template Name</li>
|
<li>Template Name</li>
|
||||||
<li>Row Header and Column Header: where the title of the excel starts</li>
|
<li>Row Header and Column Header: where the title of the excel starts</li>
|
||||||
<li>Cheme</li>
|
<li>Schema</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,96 +98,67 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
<label class="form-label"><?= htmlspecialchars($desttable, ENT_QUOTES, 'UTF-8'); ?>*</label>
|
<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>
|
<input type="text" name="target_table" class="form-control" value="<?php echo htmlspecialchars($template['target_table']); ?>" readonly required>
|
||||||
</div>
|
</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">
|
<div class="mb-3">
|
||||||
<label class="form-label">Select Client *</label>
|
<label class="form-label">Select Client *</label>
|
||||||
<select name="client_id" id="clientSelect" class="form-control" required>
|
<select name="client_id" id="clientSelect" class="form-control" required>
|
||||||
<option value="">Select a client...</option>
|
<option value="">Select a client...</option>
|
||||||
<!-- Le opzioni verranno popolate tramite JavaScript -->
|
|
||||||
</select>
|
</select>
|
||||||
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
|
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- Aggiungi il campo per selezionare lo schema -->
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Select Schema *</label>
|
<label class="form-label">Select Schema *</label>
|
||||||
<select name="schema_id" id="schemaSelect" class="form-control" required>
|
<select name="schema_id" id="schemaSelect" class="form-control" required>
|
||||||
<option value="">Select a schema...</option>
|
<option value="">Select a schema...</option>
|
||||||
<!-- Le opzioni verranno popolate tramite JavaScript -->
|
|
||||||
</select>
|
</select>
|
||||||
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Caricamento schemi in corso...</span>
|
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Caricamento schemi in corso...</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- Sezione per i campi specifici del cliente -->
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Client-Specific Fields</label>
|
<label class="form-label">Select Routine</label>
|
||||||
|
<select name="idroutine" id="routineSelect" class="form-control">
|
||||||
<!-- Intestazioni colonne -->
|
<option value="">Select a routine...</option>
|
||||||
<div class="row fw-bold text-secondary mb-1">
|
<?php foreach ($routines as $routine): ?>
|
||||||
<div class="col-md-3">Field Name</div>
|
<option value="<?php echo $routine['idroutine']; ?>" <?php echo ($template['idroutine'] ?? '') == $routine['idroutine'] ? 'selected' : ''; ?>>
|
||||||
<div class="col-md-2">Type</div>
|
<?php echo htmlspecialchars($routine['name']); ?>
|
||||||
<div class="col-md-2">Possible Values</div>
|
</option>
|
||||||
<div class="col-md-1">Required</div>
|
<?php endforeach; ?>
|
||||||
<div class="col-md-2">Export Column Name</div>
|
</select>
|
||||||
<div class="col-md-1">Default Value</div>
|
<div id="routineDetails" class="mt-2" style="display: none;">
|
||||||
<div class="col-md-1">Actions</div>
|
<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>
|
||||||
|
|
||||||
<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>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" class="btn btn-primary"><?= htmlspecialchars($savechanges, ENT_QUOTES, 'UTF-8'); ?></button>
|
<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>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end page wrapper -->
|
|
||||||
<!--start overlay-->
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<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>
|
<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'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</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>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
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 form = document.getElementById("editTemplateForm");
|
||||||
const addFieldButton = document.getElementById("addField");
|
|
||||||
const container = document.getElementById("clientSpecificFields");
|
|
||||||
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
|
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
|
||||||
const schemaLoadingStatus = document.getElementById("schemaLoadingStatus");
|
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) {
|
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
||||||
console.error("One or more DOM elements not found:", {
|
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
||||||
form,
|
|
||||||
addFieldButton,
|
|
||||||
container,
|
|
||||||
clientLoadingStatus,
|
|
||||||
schemaLoadingStatus
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("All DOM elements found");
|
// Inizializza Select2
|
||||||
|
|
||||||
// Controllo che jQuery sia caricato
|
|
||||||
if (typeof jQuery === 'undefined') {
|
|
||||||
console.error("jQuery non è caricato!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inizializza Select2 sulla tendina dei clienti
|
|
||||||
$('#clientSelect').select2({
|
$('#clientSelect').select2({
|
||||||
placeholder: "Search for a client...",
|
placeholder: "Search for a client...",
|
||||||
allowClear: true
|
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({
|
$('#schemaSelect').select2({
|
||||||
placeholder: "Search for a schema...",
|
placeholder: "Search for a schema...",
|
||||||
allowClear: true
|
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() {
|
async function loadClients() {
|
||||||
try {
|
try {
|
||||||
clientLoadingStatus.style.display = 'inline';
|
clientLoadingStatus.style.display = 'inline';
|
||||||
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_clienti.php", {
|
const response = await fetch("get_clienti.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const data = await response.json();
|
||||||
const text = await response.text();
|
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
console.log("Risposta raw (clienti):", text);
|
const select = document.getElementById("clientSelect");
|
||||||
const data = JSON.parse(text);
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
data.value.forEach(client => {
|
||||||
if (!response.ok) {
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
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); ?>)) {
|
||||||
if (data.value && Array.isArray(data.value)) {
|
option.selected = true;
|
||||||
const select = document.getElementById("clientSelect");
|
}
|
||||||
select.innerHTML = '<option value="">Select a client...</option>';
|
select.add(option);
|
||||||
data.value.forEach(client => {
|
});
|
||||||
const nome = client.Nominativo || "Nome non disponibile";
|
$(select).trigger('change');
|
||||||
const id = client.IdCliente || "ID non disponibile";
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
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"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Errore nel caricamento dei clienti:", error);
|
|
||||||
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
@@ -357,50 +248,37 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
|
||||||
clientLoadingStatus.style.display = 'none';
|
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carica gli schemi al caricamento della pagina
|
// Carica gli schemi
|
||||||
async function loadSchemas() {
|
async function loadSchemas() {
|
||||||
try {
|
try {
|
||||||
schemaLoadingStatus.style.display = 'inline';
|
schemaLoadingStatus.style.display = 'inline';
|
||||||
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_schemi.php", {
|
const response = await fetch("get_schemi.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const data = await response.json();
|
||||||
const text = await response.text();
|
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
console.log("Risposta raw (schemi):", text);
|
|
||||||
const data = JSON.parse(text);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const select = document.getElementById("schemaSelect");
|
const select = document.getElementById("schemaSelect");
|
||||||
select.innerHTML = '<option value="">Select a schema...</option>';
|
select.innerHTML = '<option value="">Select a schema...</option>';
|
||||||
data.value.forEach(schema => {
|
data.value.forEach(schema => {
|
||||||
const nome = schema.Nome || "Nome non disponibile";
|
const nome = schema.Nome || "Nome non disponibile";
|
||||||
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
||||||
const optionText = `${nome.trim()} (ID: ${id})`;
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
const option = new Option(optionText, id);
|
if (parseInt(id) === parseInt(<?php echo json_encode($template['idschema'] ?? 0); ?>)) {
|
||||||
if (parseInt(id) === parseInt(templateSchemaId)) {
|
|
||||||
option.selected = true;
|
option.selected = true;
|
||||||
}
|
}
|
||||||
select.add(option);
|
select.add(option);
|
||||||
});
|
});
|
||||||
$(select).trigger('change');
|
$(select).trigger('change');
|
||||||
console.log("Schemi caricati con successo.");
|
|
||||||
schemaLoadingStatus.textContent = "Schemi caricati.";
|
schemaLoadingStatus.textContent = "Schemi caricati.";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Errore nel caricamento degli schemi:", error);
|
|
||||||
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
@@ -409,169 +287,68 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => schemaLoadingStatus.style.display = 'none', 2000);
|
||||||
schemaLoadingStatus.style.display = 'none';
|
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carica i dati in sequenza
|
// Carica i dati
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
try {
|
try {
|
||||||
await loadClients();
|
await loadClients();
|
||||||
await loadSchemas();
|
await loadSchemas();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Errore nel caricamento dei dati:", error);
|
Swal.fire({
|
||||||
}
|
title: "Errore!",
|
||||||
}
|
text: "Errore nel caricamento dei dati: " + error.message,
|
||||||
|
icon: "error",
|
||||||
loadData();
|
confirmButtonText: "OK"
|
||||||
|
|
||||||
// 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;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
// Submit del form
|
||||||
form.addEventListener("submit", function(e) {
|
form.addEventListener("submit", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log("Form submitted");
|
|
||||||
|
|
||||||
let formData = new FormData(this);
|
let formData = new FormData(this);
|
||||||
|
|
||||||
// Aggiungi il nome del cliente selezionato a FormData
|
|
||||||
const clientSelect = document.getElementById("clientSelect");
|
const clientSelect = document.getElementById("clientSelect");
|
||||||
const clientId = clientSelect.value;
|
const clientId = clientSelect.value;
|
||||||
const selectedClientOption = clientSelect.options[clientSelect.selectedIndex];
|
const selectedClientOption = clientSelect.options[clientSelect.selectedIndex];
|
||||||
|
|
||||||
// Validazione: assicurati che un cliente sia selezionato
|
|
||||||
if (!clientId) {
|
if (!clientId) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
@@ -582,22 +359,18 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estrai il nome del cliente in modo più robusto
|
|
||||||
let clientName = "";
|
let clientName = "";
|
||||||
if (selectedClientOption) {
|
if (selectedClientOption) {
|
||||||
const optionText = selectedClientOption.text.trim();
|
const optionText = selectedClientOption.text.trim();
|
||||||
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
clientName = nameMatch ? nameMatch[1].trim() : optionText;
|
clientName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append("client_name", clientName);
|
formData.append("client_name", clientName);
|
||||||
|
|
||||||
// Aggiungi l'ID e il nome dello schema selezionato a FormData
|
|
||||||
const schemaSelect = document.getElementById("schemaSelect");
|
const schemaSelect = document.getElementById("schemaSelect");
|
||||||
const schemaId = schemaSelect.value;
|
const schemaId = schemaSelect.value;
|
||||||
const selectedSchemaOption = schemaSelect.options[schemaSelect.selectedIndex];
|
const selectedSchemaOption = schemaSelect.options[schemaSelect.selectedIndex];
|
||||||
|
|
||||||
// Validazione: assicurati che uno schema sia selezionato
|
|
||||||
if (!schemaId) {
|
if (!schemaId) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
@@ -608,63 +381,18 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estrai il nome dello schema in modo più robusto
|
|
||||||
let schemaName = "";
|
let schemaName = "";
|
||||||
if (selectedSchemaOption) {
|
if (selectedSchemaOption) {
|
||||||
const optionText = selectedSchemaOption.text.trim();
|
const optionText = selectedSchemaOption.text.trim();
|
||||||
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append("idschema", schemaId);
|
formData.append("idschema", schemaId);
|
||||||
formData.append("schemamaname", schemaName);
|
formData.append("schemaname", schemaName);
|
||||||
|
|
||||||
// Log per debug
|
// Aggiungi idroutine
|
||||||
console.log("Client ID:", clientId);
|
const routineId = routineSelect.value;
|
||||||
console.log("Client Name:", clientName);
|
formData.append("idroutine", routineId);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("process_edit_template_xls.php", {
|
fetch("process_edit_template_xls.php", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -672,7 +400,6 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log("Fetch response:", data);
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Successo!",
|
title: "Successo!",
|
||||||
@@ -692,7 +419,6 @@ if (json_last_error() !== JSON_ERROR_NONE) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error("Errore Fetch:", error);
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Si è verificato un errore imprevisto.",
|
text: "Si è verificato un errore imprevisto.",
|
||||||
|
|||||||
@@ -11,3 +11,304 @@
|
|||||||
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: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:49:24 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
2025-08-26 16:50:23 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
2025-08-26 16:50:23 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
2025-09-08 08:39:17 - Risposta non JSON valida: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"><edmx:DataServices><Schema Namespace="DevExpress.ExpressApp.SystemModule" xmlns="http://docs.oasis-open.org/odata/ns/edm"><EntityType Name="DashboardViewItemDescriptor"><Key><PropertyRef Name="ViewId" /></Key><Property Name="ViewId" Type="Edm.String" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem" BaseType="DevExpress.ExpressApp.NonPersistentLiteObject" Abstract="true"><Property Name="Visibility" Type="DevExpress.ExpressApp.Editors.ViewItemVisibility" Nullable="false" /></EntityType><EntityType Name="DashboardOrganizationItem_1OfIModelDashboardViewItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem" Abstract="true" /><EntityType Name="ViewDashboardOrganizationItem" BaseType="DevExpress.ExpressApp.SystemModule.DashboardOrganizationItem_1OfIModelDashboardViewItem"><Property Name="ObjectType" Type="System.Type" /><Proper
|
||||||
|
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"}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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()]);
|
||||||
|
}
|
||||||
@@ -1,24 +1,91 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Torna al livello di public per trovare vendor/
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
// Disabilita la visualizzazione degli errori PHP per evitare output HTML
|
// Disable PHP error display
|
||||||
ini_set('display_errors', '0');
|
ini_set('display_errors', '0');
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$api = VisualLimsApiClient::getInstance();
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv
|
||||||
$data = $api->get("Cliente"); // Recupera i clienti
|
|
||||||
|
|
||||||
// Salva la risposta in un file per debug
|
// In simulate mode: return fake clients built from idclient values already in datadb.
|
||||||
file_put_contents(__DIR__ . '/clienti_response.json', json_encode($data));
|
// 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);
|
echo json_encode($data);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode([
|
$errorResponse = [
|
||||||
'error' => $e->getMessage()
|
'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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
// get_fixed_field_data.php
|
||||||
|
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once dirname(__FILE__) . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
$field = $_GET['field'] ?? ''; // es: MoltiplicatorePrezzo, AnagraficaCertestObject, ...
|
||||||
|
|
||||||
|
if (!$field) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Parametro "field" mancante']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$api = VisualLimsApiClient::getInstance(); // also loads dotenv as a side-effect
|
||||||
|
$simulate = ($_ENV['SIMULATE_EXPORT_LIMS'] ?? '') === 'true';
|
||||||
|
$base_url = 'https://93.43.5.102/limsapi/api/odata/';
|
||||||
|
|
||||||
|
$data = null;
|
||||||
|
$endpoint = null;
|
||||||
|
$cache_file = null;
|
||||||
|
$options = []; // qui puoi aggiungere filtri/ordering per campo se serve
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch ($field) {
|
||||||
|
case 'MoltiplicatorePrezzo':
|
||||||
|
$endpoint = 'MoltiplicatorePrezzi';
|
||||||
|
$cache_file = __DIR__ . '/cache/moltiplicatori_prezzo.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'AnagraficaCertestObject':
|
||||||
|
$endpoint = 'AnagraficaCertestObject';
|
||||||
|
$cache_file = __DIR__ . '/cache/anagrafica_certest_object.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'AnagraficaCertestService':
|
||||||
|
$endpoint = 'AnagraficaCertestService';
|
||||||
|
$cache_file = __DIR__ . '/cache/anagrafica_certest_service.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ClienteResponsabile':
|
||||||
|
$id_cliente = (int)($_GET['id_cliente'] ?? 0);
|
||||||
|
if ($id_cliente <= 0) {
|
||||||
|
if (!$simulate) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Manca o invalido id_cliente']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$id_cliente = 1; // dummy — mock ignores the actual ID
|
||||||
|
}
|
||||||
|
$endpoint = "Cliente($id_cliente)?\$expand=Responsabili";
|
||||||
|
$cache_file = __DIR__ . '/cache/cliente_responsabili_' . $id_cliente . '.json';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// case 'FuturoCampo5':
|
||||||
|
// $endpoint = 'QualcosaElse';
|
||||||
|
// break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => "Campo non supportato: $field"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caching skipped in simulate mode to avoid polluting real-data cache files
|
||||||
|
if (!$simulate && $cache_file && file_exists($cache_file) && (time() - filemtime($cache_file) < 3600)) { // 1 ora
|
||||||
|
$data = json_decode(file_get_contents($cache_file), true);
|
||||||
|
} else {
|
||||||
|
$data = $api->get($endpoint, $options);
|
||||||
|
|
||||||
|
if (!$simulate && $cache_file) {
|
||||||
|
file_put_contents($cache_file, json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log ultimo URL (opzionale, per debug)
|
||||||
|
$full_url = $base_url . $endpoint . ($options ? '?' . http_build_query($options) : '');
|
||||||
|
file_put_contents(__DIR__ . '/last_urls.log', date('c') . " - $field - $full_url\n", FILE_APPEND);
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
file_put_contents(
|
||||||
|
__DIR__ . '/error_log.txt',
|
||||||
|
date('Y-m-d H:i:s') . " [$field] " . $e->getMessage() . PHP_EOL,
|
||||||
|
FILE_APPEND
|
||||||
|
);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,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);
|
||||||
|
}
|
||||||
@@ -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()]);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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()]);
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ error_reporting(E_ALL);
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$api = VisualLimsApiClient::getInstance();
|
$api = VisualLimsApiClient::getInstance();
|
||||||
$rapporto_id = 515081;
|
$rapporto_id = 533329;
|
||||||
|
|
||||||
// Costruzione manuale dell'endpoint con espansione annidata
|
// Costruzione manuale dell'endpoint con espansione annidata
|
||||||
$endpoint = "Rapporto($rapporto_id)?\$expand=CampioniDatiRapporto(\$expand=AnalisiDatiRapporto,CustomFieldsDatiRapporto)";
|
$endpoint = "Rapporto($rapporto_id)?\$expand=CampioniDatiRapporto(\$expand=AnalisiDatiRapporto,CustomFieldsDatiRapporto)";
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ foreach ($allMappings as $mapping) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$mainFieldMapping) {
|
if (!$mainFieldMapping) {
|
||||||
$mainFieldMapping = reset(array_filter($allMappings, fn($m) => !$m['is_manual']));
|
$filtered = array_filter($allMappings, fn($m) => !$m['is_manual']);
|
||||||
|
$mainFieldMapping = reset($filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve data from datadb
|
// Retrieve data from datadb
|
||||||
@@ -662,6 +663,11 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
} else {
|
} else {
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
|
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)
|
// Campi automatici (escluso main_field)
|
||||||
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
|
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
@@ -712,11 +718,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
$manualIndex++;
|
$manualIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Colonne status, Import Reference Code, filename_import
|
// Colonne Import Reference Code, filename_import
|
||||||
$fixedColumnsReduced = ['status'];
|
|
||||||
foreach ($fixedColumnsReduced as $col) {
|
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
|
|
||||||
}
|
|
||||||
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>"; // Import Reference Code
|
||||||
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // filename_import
|
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // filename_import
|
||||||
// AWB Number e Tracking Info
|
// AWB Number e Tracking Info
|
||||||
@@ -734,6 +736,12 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mainFieldMapping['field_label']) . "<div class='resizer'></div></div>";
|
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++;
|
$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)
|
// Header per campi automatici (escluso main_field)
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
|
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
|
||||||
@@ -748,12 +756,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
$headerIndex++;
|
$headerIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Header per status, Import Reference Code, filename_import
|
// Header per Import Reference Code, filename_import
|
||||||
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++;
|
|
||||||
}
|
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>Import Reference Code<div class='resizer'></div></div>";
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>Import Reference Code<div class='resizer'></div></div>";
|
||||||
$headerIndex++;
|
$headerIndex++;
|
||||||
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>File<div class='resizer'></div></div>";
|
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>File<div class='resizer'></div></div>";
|
||||||
@@ -770,13 +773,11 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
<div style="display: flex; gap: 5px; justify-content: center;">
|
<div style="display: flex; gap: 5px; justify-content: center;">
|
||||||
<?php if (!$is_readonly): ?>
|
<?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>
|
<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>
|
||||||
<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>
|
|
||||||
<?php else: ?>
|
<?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>
|
<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>
|
||||||
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; flex: 1;" disabled><i class="fas fa-camera"></i></button>
|
|
||||||
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; flex: 1;" disabled><i class="fas fa-puzzle-piece"></i></button>
|
|
||||||
<?php endif; ?>
|
<?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>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
@@ -806,6 +807,25 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
echo "</div>";
|
echo "</div>";
|
||||||
$cellIndex++;
|
$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 === '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++;
|
||||||
|
}
|
||||||
// Campi automatici (escluso main_field)
|
// Campi automatici (escluso main_field)
|
||||||
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
|
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
@@ -863,20 +883,6 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
$manualIndex++;
|
$manualIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Colonna status
|
|
||||||
$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 === 'status') {
|
|
||||||
$badgeClass = $value === 'i' ? 'status-i' : ($value === 'P' ? 'status-P' : 'status-l');
|
|
||||||
$badgeText = $value === 'i' ? 'Imported' : ($value === 'P' ? 'Progress' : 'LIMS');
|
|
||||||
echo "<span class='status-badge $badgeClass'>" . htmlspecialchars($badgeText) . "</span>";
|
|
||||||
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value ?? 'i') . "'>";
|
|
||||||
}
|
|
||||||
echo "</div>";
|
|
||||||
$cellIndex++;
|
|
||||||
}
|
|
||||||
// Colonne Import Reference Code e filename_import
|
// 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 "<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 "<span>" . htmlspecialchars($row['importreferencecode']) . "</span>";
|
||||||
@@ -948,6 +954,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|||||||
</div>
|
</div>
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
|
||||||
<script src="photos.js"></script>
|
<script src="photos.js"></script>
|
||||||
<script src="parts.js"></script>
|
<script src="parts.js"></script>
|
||||||
<script src="tracking.js"></script>
|
<script src="tracking.js"></script>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1995
-296
File diff suppressed because it is too large
Load Diff
@@ -17,23 +17,28 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !i
|
|||||||
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
|
header("Location: xlstemplates_grid.php?status=error&message=" . urlencode("Richiesta non valida"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$template_id = intval($_POST['template_id']);
|
$template_id = intval($_POST['template_id']);
|
||||||
$selected_rows = $_POST['selected_rows'];
|
$selected_rows = array_map('intval', $_POST['selected_rows']);
|
||||||
$columns = json_decode($_POST['columns'], true); // Header dell'XLS
|
$columns = json_decode(urldecode($_POST['columns'] ?? '[]'), true);
|
||||||
$rows = json_decode($_POST['rows'], true); // Dati dell'XLS
|
$rows = json_decode(urldecode($_POST['rows'] ?? '[]'), true);
|
||||||
|
$excelrows = json_decode(urldecode($_POST['excelrows'] ?? '[]'), true);
|
||||||
|
|
||||||
$newFilename = htmlspecialchars($_POST['filename']);
|
$newFilename = htmlspecialchars($_POST['filename']);
|
||||||
|
|
||||||
$_SESSION['template_id'] = $template_id;
|
$_SESSION['template_id'] = $template_id;
|
||||||
$_SESSION['selected_rows'] = $selected_rows;
|
$_SESSION['selected_rows'] = $selected_rows;
|
||||||
$_SESSION['columns'] = $columns;
|
$_SESSION['columns'] = $columns;
|
||||||
$_SESSION['rows'] = $rows;
|
$_SESSION['rows'] = $rows;
|
||||||
|
$_SESSION['excelrows'] = $excelrows;
|
||||||
$_SESSION['filename'] = $newFilename;
|
$_SESSION['filename'] = $newFilename;
|
||||||
|
|
||||||
error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows));
|
error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows));
|
||||||
error_log("Columns: " . json_encode($columns));
|
error_log("Columns: " . json_encode($columns));
|
||||||
error_log("Rows: " . json_encode($rows));
|
error_log("Rows: " . json_encode($rows));
|
||||||
|
error_log("Excelrows: " . json_encode($excelrows));
|
||||||
|
|
||||||
$user_id = $iduserlogin ?? 1; // Default a 1 se non definito
|
$user_id = $iduserlogin ?? 1;
|
||||||
|
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
@@ -60,30 +65,45 @@ foreach ($allMappings as $mapping) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserisci le righe selezionate in datadb (solo campi generici con templateid)
|
// Inserisci le righe selezionate in datadb
|
||||||
$insertedIds = [];
|
$insertedIds = [];
|
||||||
foreach ($selected_rows as $rowIndex) {
|
foreach ($selected_rows as $rowIndex) {
|
||||||
$row = $rows[$rowIndex];
|
$row = $rows[$rowIndex] ?? null;
|
||||||
|
$excelrow = $excelrows[$rowIndex] ?? null;
|
||||||
|
|
||||||
|
if ($row === null || $excelrow === null) {
|
||||||
|
error_log("Errore: riga o excelrow mancante per rowIndex $rowIndex");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recupera l'idclient di default dal template
|
||||||
|
$template_stmt = $pdo->prepare("SELECT idclient FROM excel_templates WHERE id = ?");
|
||||||
|
$template_stmt->execute([$template_id]);
|
||||||
|
$template = $template_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$default_idclient = $template['idclient'] ?? null;
|
||||||
|
|
||||||
$values = [
|
$values = [
|
||||||
$template_id, // templateid
|
$template_id,
|
||||||
$importReferenceCode, // importreferencecode
|
$importReferenceCode,
|
||||||
$newFilename, // filename_import
|
$newFilename,
|
||||||
'i', // status
|
'i',
|
||||||
$user_id, // user_id
|
$user_id,
|
||||||
null, // limscode
|
null,
|
||||||
date('Y-m-d') // importdate
|
date('Y-m-d'),
|
||||||
|
$excelrow,
|
||||||
|
$default_idclient // Aggiungi idclient
|
||||||
];
|
];
|
||||||
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
$sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate, excelrow, idclient) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
$stmt = $pdo->prepare($sql);
|
$stmt = $pdo->prepare($sql);
|
||||||
$stmt->execute($values);
|
$stmt->execute($values);
|
||||||
|
|
||||||
$iddatadb = $pdo->lastInsertId();
|
$iddatadb = $pdo->lastInsertId();
|
||||||
$insertedIds[] = $iddatadb;
|
$insertedIds[] = $iddatadb;
|
||||||
|
|
||||||
// Inserisci tutti i campi (automatici e manuali) in import_data_details
|
// Inserisci tutti i campi in import_data_details
|
||||||
foreach ($allMappings as $mapping) {
|
foreach ($allMappings as $mapping) {
|
||||||
$fieldValue = null;
|
$fieldValue = null;
|
||||||
if (!$mapping['is_manual']) { // Campi automatici dall'XLS
|
if (!$mapping['is_manual']) {
|
||||||
$excelColumn = trim($mapping['excel_column']);
|
$excelColumn = trim($mapping['excel_column']);
|
||||||
$excelColumnIndex = array_search($excelColumn, array_map('trim', $columns));
|
$excelColumnIndex = array_search($excelColumn, array_map('trim', $columns));
|
||||||
if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') {
|
if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') {
|
||||||
@@ -109,7 +129,7 @@ foreach ($selected_rows as $rowIndex) {
|
|||||||
$fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? '');
|
$fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? '');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else { // Campi manuali
|
} else {
|
||||||
$fieldValue = $mapping['manual_default'] ?? '';
|
$fieldValue = $mapping['manual_default'] ?? '';
|
||||||
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
|
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
|
||||||
$fieldValue = date('Y-m-d');
|
$fieldValue = date('Y-m-d');
|
||||||
@@ -129,29 +149,26 @@ $_SESSION['inserted_ids'] = $insertedIds;
|
|||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
'template_id' => $template_id,
|
'template_id' => $template_id,
|
||||||
'filename' => $newFilename,
|
'filename' => $newFilename,
|
||||||
];
|
];
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<form id="redirectForm" action="import_edit2.php" method="post">
|
<form id="redirectForm" action="import_edit2.php" method="post">
|
||||||
<input type="hidden" name="template_id" value="<?= htmlspecialchars($template_id) ?>">
|
<input type="hidden" name="template_id" value="<?= htmlspecialchars($template_id) ?>">
|
||||||
<input type="hidden" name="filename" value="<?= htmlspecialchars($newFilename) ?>">
|
<input type="hidden" name="filename" value="<?= htmlspecialchars($newFilename) ?>">
|
||||||
|
<?php foreach ($selected_rows as $row): ?>
|
||||||
<?php foreach ($selected_rows as $row): ?>
|
<input type="hidden" name="selected_rows[]" value="<?= htmlspecialchars($row) ?>">
|
||||||
<input type="hidden" name="selected_rows[]" value="<?= htmlspecialchars($row) ?>">
|
<?php endforeach; ?>
|
||||||
<?php endforeach; ?>
|
<?php foreach ($insertedIds as $id): ?>
|
||||||
|
<input type="hidden" name="inserted_ids[]" value="<?= htmlspecialchars($id) ?>">
|
||||||
<?php foreach ($insertedIds as $id): ?>
|
<?php endforeach; ?>
|
||||||
<input type="hidden" name="inserted_ids[]" value="<?= htmlspecialchars($id) ?>">
|
<input type="hidden" name="columns" value='<?= json_encode($columns) ?>'>
|
||||||
<?php endforeach; ?>
|
<input type="hidden" name="rows" value='<?= json_encode($rows) ?>'>
|
||||||
|
<input type="hidden" name="excelrows" value='<?= json_encode($excelrows) ?>'>
|
||||||
<input type="hidden" name="columns" value='<?= json_encode($columns) ?>'>
|
</form>
|
||||||
<input type="hidden" name="rows" value='<?= json_encode($rows) ?>'>
|
<script>
|
||||||
</form>
|
document.getElementById('redirectForm').submit();
|
||||||
<script>
|
</script>
|
||||||
document.getElementById('redirectForm').submit();
|
|
||||||
</script>
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
|
?>
|
||||||
+251
-127
@@ -21,6 +21,11 @@ if (!$template) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifica i mapping
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM template_mapping WHERE template_id = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$hasMappings = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// Debug del template
|
// Debug del template
|
||||||
error_log("Loaded template: " . print_r($template, true));
|
error_log("Loaded template: " . print_r($template, true));
|
||||||
?>
|
?>
|
||||||
@@ -33,6 +38,7 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
.table-container {
|
.table-container {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@@ -115,6 +121,16 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-filters th {
|
||||||
|
background: #ffffff;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-filters input {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<title><?= htmlspecialchars($template['name']) ?> - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title><?= htmlspecialchars($template['name']) ?> - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
@@ -140,43 +156,55 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<!-- Form per caricare il file -->
|
<?php if (!$hasMappings): ?>
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
Nessun mapping trovato per questo template. Configura i mapping prima di procedere.
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<form id="uploadForm" enctype="multipart/form-data" class="mb-4">
|
<form id="uploadForm" enctype="multipart/form-data" class="mb-4">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="excel_file" class="form-label">Upload XLS File</label>
|
<label for="excel_file" class="form-label">Upload XLS File</label>
|
||||||
<input type="file" class="form-control" id="excel_file" name="excel_file" accept=".xls,.xlsx" required>
|
<input type="file" class="form-control" id="excel_file" name="excel_file" accept=".xls,.xlsx" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Upload</button>
|
<button type="submit" class="btn btn-primary" <?= !$hasMappings ? 'disabled' : '' ?>>Upload</button>
|
||||||
<div class="loader" id="loader"></div>
|
<div class="loader" id="loader"></div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Contenitore per messaggi di errore -->
|
|
||||||
<div id="errorContainer" class="alert alert-danger mt-3" style="display: none;"></div>
|
<div id="errorContainer" class="alert alert-danger mt-3" style="display: none;"></div>
|
||||||
|
|
||||||
<!-- Contenitore per la tabella -->
|
|
||||||
<div id="tableContainer"></div>
|
<div id="tableContainer"></div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="routineConfirmModal" tabindex="-1" aria-labelledby="routineConfirmModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="routineConfirmModalLabel">Conferma Applicazione Routine</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p><strong>Routine:</strong> <span id="routineName"></span></p>
|
||||||
|
<p><strong>Descrizione:</strong> <span id="routineDescription"></span></p>
|
||||||
|
<p>Vuoi applicare questa routine al file caricato?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="cancelRoutineBtn">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="confirmRoutineBtn">Applica</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end page wrapper -->
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<div class="overlay toggle-icon"></div>
|
||||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
<?php include('include/footer.php'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
<!--end wrapper-->
|
|
||||||
|
|
||||||
<!-- search modal -->
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
|
||||||
<?php //include('include/searchmodal.php');
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script>
|
||||||
?>
|
|
||||||
<!-- end search modal -->
|
|
||||||
|
|
||||||
<!--start switcher-->
|
|
||||||
<?php //include('include/themeswitcher.php');
|
|
||||||
?>
|
|
||||||
<!--end switcher-->
|
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
@@ -184,6 +212,12 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
const loader = document.getElementById('loader');
|
const loader = document.getElementById('loader');
|
||||||
const errorContainer = document.getElementById('errorContainer');
|
const errorContainer = document.getElementById('errorContainer');
|
||||||
const tableContainer = document.getElementById('tableContainer');
|
const tableContainer = document.getElementById('tableContainer');
|
||||||
|
const routineModal = new bootstrap.Modal(document.getElementById('routineConfirmModal'));
|
||||||
|
const confirmRoutineBtn = document.getElementById('confirmRoutineBtn');
|
||||||
|
const cancelRoutineBtn = document.getElementById('cancelRoutineBtn');
|
||||||
|
let routineData = null;
|
||||||
|
let excelData = null;
|
||||||
|
let responseData = null;
|
||||||
|
|
||||||
form.addEventListener('submit', function(e) {
|
form.addEventListener('submit', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -202,131 +236,221 @@ error_log("Loaded template: " . print_r($template, true));
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
console.log('Stato risposta:', response.status);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
console.log('Risposta JSON:', data);
|
||||||
loader.style.display = 'none';
|
loader.style.display = 'none';
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
errorContainer.textContent = data.error;
|
errorContainer.textContent = data.error;
|
||||||
errorContainer.style.display = 'block';
|
errorContainer.style.display = 'block';
|
||||||
|
} else if (data.apply_routine) {
|
||||||
|
console.log('Routine rilevata:', data.routine_data);
|
||||||
|
routineData = data.routine_data;
|
||||||
|
excelData = data.excel_data;
|
||||||
|
responseData = data;
|
||||||
|
document.getElementById('routineName').textContent = routineData.name || 'Sconosciuta';
|
||||||
|
document.getElementById('routineDescription').textContent = routineData.instruction || 'Nessuna descrizione';
|
||||||
|
routineModal.show();
|
||||||
} else {
|
} else {
|
||||||
let html = `
|
console.log('Nessuna routine, procedo con tabella');
|
||||||
<form id="selectRowsForm" action="import_insert.php" method="POST">
|
showTable(data);
|
||||||
<input type="hidden" name="template_id" value="${data.template_id}">
|
|
||||||
<input type="hidden" name="columns" value='${JSON.stringify(data.columns)}'>
|
|
||||||
<input type="hidden" name="rows" value='${JSON.stringify(data.rows)}'>
|
|
||||||
<input type="hidden" name="filename" value="${data.filename}">
|
|
||||||
<div class="search-container">
|
|
||||||
<input type="text" id="searchInput" class="form-control" placeholder="Cerca nelle righe...">
|
|
||||||
</div>
|
|
||||||
<div class="table-container">
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th><input type="checkbox" id="selectAll"> Seleziona</th>
|
|
||||||
${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
${data.rows.map((row, index) => `
|
|
||||||
<tr>
|
|
||||||
<td><input type="checkbox" class="row-checkbox" name="selected_rows[]" value="${index}"></td>
|
|
||||||
${row.map(cell => `<td>${cell}</td>`).join('')}
|
|
||||||
</tr>
|
|
||||||
`).join('')}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary mt-3" id="proceedButton" disabled>Prosegui</button>
|
|
||||||
</form>
|
|
||||||
`;
|
|
||||||
tableContainer.innerHTML = html;
|
|
||||||
|
|
||||||
// Inizializza le variabili dopo aver inserito la tabella
|
|
||||||
const proceedButton = document.getElementById('proceedButton');
|
|
||||||
const selectAllCheckbox = document.getElementById('selectAll');
|
|
||||||
const checkboxes = document.querySelectorAll('.row-checkbox');
|
|
||||||
|
|
||||||
// Funzione per aggiornare lo stato del pulsante Prosegui
|
|
||||||
function updateProceedButton() {
|
|
||||||
proceedButton.disabled = !Array.from(checkboxes).some(cb => cb.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event listener per il checkbox "Seleziona tutto"
|
|
||||||
selectAllCheckbox.addEventListener('change', function() {
|
|
||||||
checkboxes.forEach(checkbox => {
|
|
||||||
checkbox.checked = this.checked;
|
|
||||||
});
|
|
||||||
updateProceedButton();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Event listener per i checkbox delle righe
|
|
||||||
checkboxes.forEach(checkbox => {
|
|
||||||
checkbox.addEventListener('change', function() {
|
|
||||||
console.log('Checkbox changed, checked: ', this.checked); // Debug
|
|
||||||
// Aggiorna lo stato del checkbox "Seleziona tutto"
|
|
||||||
selectAllCheckbox.checked = Array.from(checkboxes).every(cb => cb.checked);
|
|
||||||
updateProceedButton();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Aggiungi logica per il ridimensionamento delle colonne
|
|
||||||
const thElements = document.querySelectorAll('.table th');
|
|
||||||
thElements.forEach((th, index) => {
|
|
||||||
if (index === 0) return;
|
|
||||||
const resizeHandle = th.querySelector('.resize-handle');
|
|
||||||
if (resizeHandle) {
|
|
||||||
resizeHandle.addEventListener('mousedown', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const startX = e.clientX;
|
|
||||||
const startWidth = th.offsetWidth;
|
|
||||||
|
|
||||||
const onMouseMove = (e) => {
|
|
||||||
const newWidth = Math.max(50, startWidth + (e.clientX - startX));
|
|
||||||
th.style.width = `${newWidth}px`;
|
|
||||||
th.style.minWidth = `${newWidth}px`;
|
|
||||||
th.style.maxWidth = `${newWidth}px`;
|
|
||||||
|
|
||||||
const cells = document.querySelectorAll(`.table td:nth-child(${index + 1})`);
|
|
||||||
cells.forEach(cell => {
|
|
||||||
cell.style.width = `${newWidth}px`;
|
|
||||||
cell.style.minWidth = `${newWidth}px`;
|
|
||||||
cell.style.maxWidth = `${newWidth}px`;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseUp = () => {
|
|
||||||
document.removeEventListener('mousemove', onMouseMove);
|
|
||||||
document.removeEventListener('mouseup', onMouseUp);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', onMouseMove);
|
|
||||||
document.addEventListener('mouseup', onMouseUp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Aggiungi event listener per la ricerca
|
|
||||||
const searchInput = document.getElementById('searchInput');
|
|
||||||
const rows = document.querySelectorAll('.table tbody tr');
|
|
||||||
|
|
||||||
searchInput.addEventListener('input', function() {
|
|
||||||
const searchTerm = this.value.toLowerCase();
|
|
||||||
rows.forEach(row => {
|
|
||||||
const text = Array.from(row.cells).slice(1).map(cell => cell.textContent.toLowerCase()).join(' ');
|
|
||||||
row.style.display = text.includes(searchTerm) ? '' : 'none';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Abilita il pulsante se ci sono checkbox selezionate all'inizio
|
|
||||||
updateProceedButton();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
console.log('Errore fetch:', error);
|
||||||
loader.style.display = 'none';
|
loader.style.display = 'none';
|
||||||
errorContainer.textContent = 'Errore durante il caricamento del file: ' + error.message;
|
errorContainer.textContent = 'Errore durante il caricamento del file: ' + error.message;
|
||||||
errorContainer.style.display = 'block';
|
errorContainer.style.display = 'block';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
confirmRoutineBtn.addEventListener('click', function() {
|
||||||
|
console.log('Conferma routine:', routineData);
|
||||||
|
routineModal.hide();
|
||||||
|
|
||||||
|
fetch('apply_routine.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
template_id: <?= $id ?>,
|
||||||
|
filename: routineData.filename,
|
||||||
|
headerrow: routineData.headerrow,
|
||||||
|
excel_data: excelData,
|
||||||
|
routine_data: routineData
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
console.log('Stato apply_routine:', response.status);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('Risposta apply_routine:', data);
|
||||||
|
if (data.error) {
|
||||||
|
errorContainer.textContent = data.error;
|
||||||
|
errorContainer.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
showTable(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log('Errore apply_routine:', error);
|
||||||
|
errorContainer.textContent = 'Errore durante l\'applicazione della routine: ' + error.message;
|
||||||
|
errorContainer.style.display = 'block';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelRoutineBtn.addEventListener('click', function() {
|
||||||
|
console.log('Routine annullata, procedo con tabella');
|
||||||
|
routineModal.hide();
|
||||||
|
showTable(responseData);
|
||||||
|
});
|
||||||
|
|
||||||
|
function showTable(data) {
|
||||||
|
console.log('Mostro tabella con dati:', data);
|
||||||
|
let html = `
|
||||||
|
<form id="selectRowsForm" action="import_insert.php" method="POST">
|
||||||
|
<input type="hidden" name="template_id" value="${data.template_id}">
|
||||||
|
<input type="hidden" name="columns" value="${encodeURIComponent(JSON.stringify(data.columns))}">
|
||||||
|
<input type="hidden" name="rows" value="${encodeURIComponent(JSON.stringify(data.rows))}">
|
||||||
|
<input type="hidden" name="excelrows" value="${encodeURIComponent(JSON.stringify(data.excel_data.map(r => r.excelrow)))}">
|
||||||
|
|
||||||
|
<input type="hidden" name="filename" value="${data.filename}">
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><input type="checkbox" id="selectAll"> Seleziona</th>
|
||||||
|
${data.columns.map(col => `<th>${col || 'Colonna senza nome'}<div class="resize-handle"></div></th>`).join('')}
|
||||||
|
</tr>
|
||||||
|
<tr class="column-filters">
|
||||||
|
<th></th>
|
||||||
|
${data.columns.map((col, i) => `
|
||||||
|
<th>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control form-control-sm column-filter"
|
||||||
|
data-col-index="${i}"
|
||||||
|
placeholder="Filter...">
|
||||||
|
</th>
|
||||||
|
`).join('')}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${data.excel_data.map((row, index) => `
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" class="row-checkbox" name="selected_rows[]" value="${index}" data-excelrow="${row.excelrow}"></td>
|
||||||
|
${row.data.map(cell => `<td>${cell}</td>`).join('')}
|
||||||
|
</tr>
|
||||||
|
`).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="proceedButton" disabled>Prosegui</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
tableContainer.innerHTML = html;
|
||||||
|
|
||||||
|
const proceedButton = document.getElementById('proceedButton');
|
||||||
|
const selectAllCheckbox = document.getElementById('selectAll');
|
||||||
|
const checkboxes = document.querySelectorAll('.row-checkbox');
|
||||||
|
|
||||||
|
function updateProceedButton() {
|
||||||
|
proceedButton.disabled = !Array.from(checkboxes).some(cb => cb.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAllCheckbox.addEventListener('change', function() {
|
||||||
|
checkboxes.forEach(checkbox => {
|
||||||
|
checkbox.checked = this.checked;
|
||||||
|
});
|
||||||
|
updateProceedButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
checkboxes.forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
|
console.log('Checkbox changed, checked:', this.checked, 'excelrow:', this.dataset.excelrow);
|
||||||
|
selectAllCheckbox.checked = Array.from(checkboxes).every(cb => cb.checked);
|
||||||
|
updateProceedButton();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const thElements = document.querySelectorAll('.table th');
|
||||||
|
thElements.forEach((th, index) => {
|
||||||
|
if (index === 0) return;
|
||||||
|
const resizeHandle = th.querySelector('.resize-handle');
|
||||||
|
if (resizeHandle) {
|
||||||
|
resizeHandle.addEventListener('mousedown', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const startX = e.clientX;
|
||||||
|
const startWidth = th.offsetWidth;
|
||||||
|
|
||||||
|
const onMouseMove = (e) => {
|
||||||
|
const newWidth = Math.max(50, startWidth + (e.clientX - startX));
|
||||||
|
th.style.width = `${newWidth}px`;
|
||||||
|
th.style.minWidth = `${newWidth}px`;
|
||||||
|
th.style.maxWidth = `${newWidth}px`;
|
||||||
|
|
||||||
|
const cells = document.querySelectorAll(`.table td:nth-child(${index + 1})`);
|
||||||
|
cells.forEach(cell => {
|
||||||
|
cell.style.width = `${newWidth}px`;
|
||||||
|
cell.style.minWidth = `${newWidth}px`;
|
||||||
|
cell.style.maxWidth = `${newWidth}px`;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = () => {
|
||||||
|
document.removeEventListener('mousemove', onMouseMove);
|
||||||
|
document.removeEventListener('mouseup', onMouseUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onMouseMove);
|
||||||
|
document.addEventListener('mouseup', onMouseUp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = document.querySelectorAll('.table tbody tr');
|
||||||
|
const filterInputs = document.querySelectorAll('.column-filter');
|
||||||
|
|
||||||
|
// Stato filtri: key = colIndex, value = testo
|
||||||
|
const activeFilters = {};
|
||||||
|
|
||||||
|
function applyColumnFilters() {
|
||||||
|
rows.forEach(row => {
|
||||||
|
// Le celle di data partono da index 1 (perché index 0 è checkbox)
|
||||||
|
let visible = true;
|
||||||
|
|
||||||
|
for (const [colIndexStr, filterValue] of Object.entries(activeFilters)) {
|
||||||
|
const colIndex = parseInt(colIndexStr, 10); // 0..N-1 sulle colonne dati
|
||||||
|
const cell = row.cells[colIndex + 1]; // +1 per saltare la colonna checkbox
|
||||||
|
|
||||||
|
const cellText = (cell?.textContent || '').toLowerCase();
|
||||||
|
const searchText = (filterValue || '').toLowerCase().trim();
|
||||||
|
|
||||||
|
if (searchText && !cellText.includes(searchText)) {
|
||||||
|
visible = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
row.style.display = visible ? '' : 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
filterInputs.forEach(input => {
|
||||||
|
input.addEventListener('input', function() {
|
||||||
|
const colIndex = this.dataset.colIndex; // string
|
||||||
|
activeFilters[colIndex] = this.value;
|
||||||
|
applyColumnFilters();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
updateProceedButton();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -35,8 +35,6 @@ $kindofrole = $user->present()->role_id;
|
|||||||
//$iduserlogin="1";
|
//$iduserlogin="1";
|
||||||
//$nameuser="Claudio";
|
//$nameuser="Claudio";
|
||||||
//$emailuser="info@claudiosironi.com";
|
//$emailuser="info@claudiosironi.com";
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
if (session_status() == PHP_SESSION_NONE) {
|
if (session_status() == PHP_SESSION_NONE) {
|
||||||
session_start();
|
session_start();
|
||||||
}
|
}
|
||||||
@@ -49,13 +47,8 @@ $_SESSION["emailuser"] = $emailuser;
|
|||||||
$_SESSION["photouser"] = $avatar;
|
$_SESSION["photouser"] = $avatar;
|
||||||
$photouser = $_SESSION["photouser"];
|
$photouser = $_SESSION["photouser"];
|
||||||
$photousername = basename($avatar);
|
$photousername = basename($avatar);
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
<?php //include files
|
|
||||||
|
|
||||||
|
//include files
|
||||||
require_once(__DIR__ . '/../../languages/en/general.php');
|
require_once(__DIR__ . '/../../languages/en/general.php');
|
||||||
|
|
||||||
//include("generalsettings.php");
|
//include("generalsettings.php");
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once(__DIR__ . '/../class/db-functions.php');
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL | E_STRICT);
|
||||||
|
|
||||||
|
// Inizializza la sessione
|
||||||
|
if (session_status() == PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imposta variabili di sessione di default per evitare errori
|
||||||
|
$_SESSION['iduserlogin'] = '1'; // Nessun utente loggato
|
||||||
|
$_SESSION['nameuser'] = 'Ospite';
|
||||||
|
$_SESSION['surnameuser'] = '';
|
||||||
|
$_SESSION['emailuser'] = '';
|
||||||
|
$_SESSION['photouser'] = '';
|
||||||
|
$photouser = $_SESSION['photouser'];
|
||||||
|
$photousername = '';
|
||||||
|
$iduserlogin = $_SESSION['iduserlogin'];
|
||||||
|
// Include file di lingua, se necessario
|
||||||
|
require_once(__DIR__ . '/../../languages/en/general.php');
|
||||||
@@ -41,7 +41,21 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>-->
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="javascript:;" class="has-arrow">
|
||||||
|
<div class="parent-icon"><i class="bx bx-category"></i>
|
||||||
|
</div>
|
||||||
|
<div class="menu-title">Other Functions</div>
|
||||||
|
</a>
|
||||||
|
<ul>
|
||||||
|
<li> <a href="quotations.php"><i class='bx bx-radio-circle'></i><?php echo $quotationstitle; ?></a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
<?php include('include/headscript.php'); ?>
|
<?php include('include/headscript.php');
|
||||||
|
|
||||||
|
// Recupera tutte le routine dal database
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM routine");
|
||||||
|
$stmt->execute();
|
||||||
|
$routines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<!-- Required meta tags -->
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!--favicon-->
|
|
||||||
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
<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" />
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||||
<?php include('cssinclude.php'); ?>
|
<?php include('cssinclude.php'); ?>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<title>Insert XLS Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
<title>Insert XLS Template <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!--wrapper-->
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<!--sidebar wrapper -->
|
|
||||||
<?php include('include/navbar.php'); ?>
|
<?php include('include/navbar.php'); ?>
|
||||||
<!--end sidebar wrapper -->
|
|
||||||
<!--start header -->
|
|
||||||
<?php include('include/topbar.php'); ?>
|
<?php include('include/topbar.php'); ?>
|
||||||
<!--end header -->
|
|
||||||
<!--start page wrapper -->
|
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
@@ -35,7 +37,7 @@
|
|||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li>Template Name</li>
|
<li>Template Name</li>
|
||||||
<li>Row Header and Column Header: where the title of the excel starts</li>
|
<li>Row Header and Column Header: where the title of the excel starts</li>
|
||||||
<li>Scheme and client</li>
|
<li>Schema and client</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -73,7 +75,6 @@
|
|||||||
|
|
||||||
<input type="hidden" name="target_table" value="datadb">
|
<input type="hidden" name="target_table" value="datadb">
|
||||||
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Button Size</label>
|
<label class="form-label">Button Size</label>
|
||||||
<select name="button_size" class="form-control">
|
<select name="button_size" class="form-control">
|
||||||
@@ -97,7 +98,7 @@
|
|||||||
<label class="form-label">Button Label</label>
|
<label class="form-label">Button Label</label>
|
||||||
<input type="text" name="button_label" class="form-control" value="Click Me">
|
<input type="text" name="button_label" class="form-control" value="Click Me">
|
||||||
</div>
|
</div>
|
||||||
<!-- Aggiungi il campo per selezionare il cliente -->
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Select Client *</label>
|
<label class="form-label">Select Client *</label>
|
||||||
<select name="client_id" id="clientSelect" class="form-control" required>
|
<select name="client_id" id="clientSelect" class="form-control" required>
|
||||||
@@ -105,68 +106,33 @@
|
|||||||
</select>
|
</select>
|
||||||
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
|
<span id="clientLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Recupero clienti in corso...</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- Aggiungi il campo per selezionare lo schema -->
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Select Schema *</label>
|
<label class="form-label">Select Schema *</label>
|
||||||
<select name="schema_id" id="schemaSelect" class="form-control" required>
|
<select name="schema_id" id="schemaSelect" class="form-control" required>
|
||||||
<option value="">Select a schema...</option>
|
<option value="">Select a schema...</option>
|
||||||
</select>
|
</select>
|
||||||
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Loading schemas...</span>
|
<span id="schemaLoadingStatus" class="text-muted" style="margin-left: 10px; display: none;">Caricamento schemi in corso...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- new section for specific client field -->
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Client-Specific Fields</label>
|
<label class="form-label">Select Routine</label>
|
||||||
|
<select name="idroutine" id="routineSelect" class="form-control">
|
||||||
<!-- Intestazioni -->
|
<option value="">Select a routine...</option>
|
||||||
<div class="row fw-bold text-secondary mb-1">
|
<?php foreach ($routines as $routine): ?>
|
||||||
<div class="col-md-3">Field Name</div>
|
<option value="<?php echo $routine['idroutine']; ?>">
|
||||||
<div class="col-md-2">Type</div>
|
<?php echo htmlspecialchars($routine['name']); ?>
|
||||||
<div class="col-md-2 dropdown-values">Possible Values</div>
|
</option>
|
||||||
<div class="col-md-1">Required</div>
|
<?php endforeach; ?>
|
||||||
<div class="col-md-2">Export Column Name</div>
|
</select>
|
||||||
<div class="col-md-1">Default Value</div>
|
<div id="routineDetails" class="mt-2" style="display: none;">
|
||||||
<div class="col-md-1">Actions</div>
|
<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>
|
||||||
|
|
||||||
<div id="clientSpecificFields">
|
|
||||||
<!-- Contenitore per i campi dinamici -->
|
|
||||||
<div class="client-field-row mb-2">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<input type="text" name="specific_fields[0][name]" class="form-control" placeholder="Field Name (e.g., SKU)">
|
|
||||||
</div>
|
|
||||||
<div class="col-md-2">
|
|
||||||
<select name="specific_fields[0][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[0][possible_values]" class="form-control" placeholder="Values (e.g., Red, Blue, Green)">
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
<select name="specific_fields[0][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[0][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[0][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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-primary mt-2" id="addField">Add Field</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@@ -178,125 +144,72 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end page wrapper -->
|
|
||||||
<!--start overlay-->
|
|
||||||
<div class="overlay toggle-icon"></div>
|
<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>
|
<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'); ?>
|
<?php include('include/footer.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
<!--end wrapper-->
|
|
||||||
|
|
||||||
<!-- search modal -->
|
|
||||||
<?php //include('include/searchmodal.php');
|
|
||||||
?>
|
|
||||||
<!-- end search modal -->
|
|
||||||
|
|
||||||
<!--start switcher-->
|
|
||||||
<?php //include('include/themeswitcher.php');
|
|
||||||
?>
|
|
||||||
<!--end switcher-->
|
|
||||||
|
|
||||||
<!-- Includi Select2 JS -->
|
|
||||||
|
|
||||||
<?php include('jsinclude.php'); ?>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// Debug iniziale
|
|
||||||
console.log("JavaScript is loaded and running!");
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
console.log("DOM is loaded");
|
if (typeof jQuery === 'undefined') {
|
||||||
|
alert("Errore: jQuery non è caricato. Contatta l'amministratore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const form = document.getElementById("insertTemplateForm");
|
const form = document.getElementById("insertTemplateForm");
|
||||||
const addFieldButton = document.getElementById("addField");
|
|
||||||
const container = document.getElementById("clientSpecificFields");
|
|
||||||
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
|
const clientLoadingStatus = document.getElementById("clientLoadingStatus");
|
||||||
const schemaLoadingStatus = document.getElementById("schemaLoadingStatus");
|
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) {
|
if (!form || !clientLoadingStatus || !schemaLoadingStatus || !routineSelect || !routineDetails) {
|
||||||
console.error("One or more DOM elements not found:", {
|
alert("Errore: Uno o più elementi della pagina non sono stati trovati. Contatta l'amministratore.");
|
||||||
form,
|
|
||||||
addFieldButton,
|
|
||||||
container,
|
|
||||||
clientLoadingStatus,
|
|
||||||
schemaLoadingStatus
|
|
||||||
});
|
|
||||||
return;
|
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
|
|
||||||
$('#clientSelect').select2({
|
$('#clientSelect').select2({
|
||||||
placeholder: "Search for a client...",
|
placeholder: "Search for a client...",
|
||||||
allowClear: true
|
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({
|
$('#schemaSelect').select2({
|
||||||
placeholder: "Search for a schema...",
|
placeholder: "Search for a schema...",
|
||||||
allowClear: true
|
allowClear: true
|
||||||
}).on('select2:open', function() {
|
|
||||||
console.log("Select2 initialized successfully for schemaSelect");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Funzione per caricare i clienti
|
$('#routineSelect').select2({
|
||||||
|
placeholder: "Select a routine...",
|
||||||
|
allowClear: true
|
||||||
|
});
|
||||||
|
|
||||||
async function loadClients() {
|
async function loadClients() {
|
||||||
try {
|
try {
|
||||||
clientLoadingStatus.style.display = 'inline';
|
clientLoadingStatus.style.display = 'inline';
|
||||||
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
clientLoadingStatus.textContent = 'Recupero clienti in corso...';
|
||||||
|
|
||||||
const response = await fetch("get_clienti.php", {
|
const response = await fetch("get_clienti.php", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const data = await response.json();
|
||||||
const text = await response.text();
|
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
console.log("Risposta raw (clienti):", text);
|
const select = document.getElementById("clientSelect");
|
||||||
const data = JSON.parse(text);
|
select.innerHTML = '<option value="">Select a client...</option>';
|
||||||
|
data.value.forEach(client => {
|
||||||
if (!response.ok) {
|
const nome = client.Nominativo || "Nome non disponibile";
|
||||||
throw new Error(data.error || `Errore HTTP: ${response.status}, Dettagli: ${JSON.stringify(data)}`);
|
const id = client.IdCliente || "ID non disponibile";
|
||||||
}
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
|
select.add(option);
|
||||||
if (data.value && Array.isArray(data.value)) {
|
});
|
||||||
const select = document.getElementById("clientSelect");
|
$(select).trigger('change');
|
||||||
select.innerHTML = '<option value="">Select a client...</option>';
|
clientLoadingStatus.textContent = "Clienti caricati.";
|
||||||
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);
|
|
||||||
select.add(option);
|
|
||||||
});
|
|
||||||
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"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Errore nel caricamento dei clienti:", error);
|
|
||||||
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
clientLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
@@ -305,175 +218,110 @@
|
|||||||
confirmButtonText: "OK"
|
confirmButtonText: "OK"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => clientLoadingStatus.style.display = 'none', 2000);
|
||||||
clientLoadingStatus.style.display = 'none';
|
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funzione per caricare gli schemi con ritentativi
|
|
||||||
async function loadSchemas() {
|
async function loadSchemas() {
|
||||||
const maxRetries = 3;
|
try {
|
||||||
let attempt = 0;
|
schemaLoadingStatus.style.display = 'inline';
|
||||||
|
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
||||||
while (attempt < maxRetries) {
|
const response = await fetch("get_schemi.php", {
|
||||||
try {
|
method: "GET",
|
||||||
schemaLoadingStatus.style.display = 'inline';
|
headers: {
|
||||||
schemaLoadingStatus.textContent = 'Caricamento schemi in corso...';
|
"Content-Type": "application/json"
|
||||||
|
|
||||||
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}, Dettagli: ${JSON.stringify(data)}`);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
const select = document.getElementById("schemaSelect");
|
const data = await response.json();
|
||||||
select.innerHTML = '<option value="">Select a schema...</option>';
|
if (!response.ok) throw new Error(data.error || `Errore HTTP: ${response.status}`);
|
||||||
data.value.forEach(schema => { // Nota: usa data.value per coerenza con il JSON restituito
|
const select = document.getElementById("schemaSelect");
|
||||||
const option = new Option(`${schema.Nome} (ID: ${schema.IdSchemaCustomFields})`, schema.IdSchemaCustomFields);
|
select.innerHTML = '<option value="">Select a schema...</option>';
|
||||||
select.add(option);
|
data.value.forEach(schema => {
|
||||||
});
|
const nome = schema.Nome || "Nome non disponibile";
|
||||||
|
const id = schema.IdSchemaCustomFields || "ID non disponibile";
|
||||||
schemaLoadingStatus.textContent = "Schemi caricati.";
|
const option = new Option(`${nome.trim()} (ID: ${id})`, id);
|
||||||
break; // Esci dal ciclo se la chiamata ha successo
|
select.add(option);
|
||||||
} catch (error) {
|
});
|
||||||
attempt++;
|
$(select).trigger('change');
|
||||||
console.error(`Tentativo ${attempt} fallito per schemi:`, error);
|
schemaLoadingStatus.textContent = "Schemi caricati.";
|
||||||
if (attempt === maxRetries) {
|
} catch (error) {
|
||||||
console.error("Errore finale nel caricamento degli schemi:", error);
|
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
||||||
schemaLoadingStatus.textContent = "Errore nel caricamento.";
|
Swal.fire({
|
||||||
Swal.fire({
|
title: "Errore!",
|
||||||
title: "Errore!",
|
text: "Impossibile caricare gli schemi: " + error.message,
|
||||||
text: "Impossibile caricare gli schemi: " + error.message,
|
icon: "error",
|
||||||
icon: "error",
|
confirmButtonText: "OK"
|
||||||
confirmButtonText: "OK"
|
});
|
||||||
});
|
} finally {
|
||||||
} else {
|
setTimeout(() => schemaLoadingStatus.style.display = 'none', 2000);
|
||||||
// Ritardo prima di riprovare
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (attempt === maxRetries || schemaLoadingStatus.textContent === "Schemi caricati.") {
|
|
||||||
setTimeout(() => {
|
|
||||||
schemaLoadingStatus.style.display = 'none';
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funzione combinata per caricare i dati in sequenza
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
try {
|
try {
|
||||||
await loadClients(); // Carica prima i clienti
|
await loadClients();
|
||||||
await loadSchemas(); // Poi carica gli schemi
|
await loadSchemas();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Errore nel caricamento dei dati:", error);
|
Swal.fire({
|
||||||
}
|
title: "Errore!",
|
||||||
}
|
text: "Errore nel caricamento dei dati: " + error.message,
|
||||||
|
icon: "error",
|
||||||
// Avvia il caricamento dei dati
|
confirmButtonText: "OK"
|
||||||
loadData();
|
|
||||||
|
|
||||||
// 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">
|
|
||||||
<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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
loadData();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
form.addEventListener("submit", function(e) {
|
form.addEventListener("submit", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log("Form submitted");
|
|
||||||
|
|
||||||
let formData = new FormData(this);
|
let formData = new FormData(this);
|
||||||
|
|
||||||
// Aggiungi il nome del cliente selezionato a FormData
|
|
||||||
const clientSelect = document.getElementById("clientSelect");
|
const clientSelect = document.getElementById("clientSelect");
|
||||||
const clientId = clientSelect.value;
|
const clientId = clientSelect.value;
|
||||||
const selectedClientOption = clientSelect.options[clientSelect.selectedIndex];
|
const selectedClientOption = clientSelect.options[clientSelect.selectedIndex];
|
||||||
|
|
||||||
|
if (!clientId) {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Errore!",
|
||||||
|
text: "Per favore seleziona un cliente.",
|
||||||
|
icon: "error",
|
||||||
|
confirmButtonText: "OK"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let clientName = "";
|
let clientName = "";
|
||||||
if (selectedClientOption) {
|
if (selectedClientOption) {
|
||||||
const optionText = selectedClientOption.text.trim();
|
const optionText = selectedClientOption.text.trim();
|
||||||
@@ -482,18 +330,11 @@
|
|||||||
}
|
}
|
||||||
formData.append("client_name", clientName);
|
formData.append("client_name", clientName);
|
||||||
|
|
||||||
// Aggiungi l'ID e il nome dello schema selezionato a FormData
|
|
||||||
const schemaSelect = document.getElementById("schemaSelect");
|
const schemaSelect = document.getElementById("schemaSelect");
|
||||||
const schemaId = schemaSelect.value;
|
const schemaId = schemaSelect.value;
|
||||||
const selectedSchemaOption = schemaSelect.options[schemaSelect.selectedIndex];
|
const selectedSchemaOption = schemaSelect.options[schemaSelect.selectedIndex];
|
||||||
let schemaName = "";
|
|
||||||
if (selectedSchemaOption && schemaId) {
|
if (!schemaId) {
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Per favore seleziona uno schema.",
|
text: "Per favore seleziona uno schema.",
|
||||||
@@ -503,48 +344,17 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log per debug
|
let schemaName = "";
|
||||||
console.log("Client ID:", clientId);
|
if (selectedSchemaOption) {
|
||||||
console.log("Client Name:", clientName);
|
const optionText = selectedSchemaOption.text.trim();
|
||||||
console.log("Schema ID:", schemaId);
|
const nameMatch = optionText.match(/^(.+?)(?:\s*\(ID:\s*\d+\))?$/);
|
||||||
console.log("Schema Name:", schemaName);
|
schemaName = nameMatch ? nameMatch[1].trim() : optionText;
|
||||||
|
|
||||||
// Genera il JSON per client_specific_fields
|
|
||||||
let finalSpecificFields = {};
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
formData.append("idschema", schemaId);
|
||||||
|
formData.append("schemaname", schemaName);
|
||||||
|
|
||||||
console.log("Generated JSON for client_specific_fields:", JSON.stringify(finalSpecificFields));
|
const routineId = routineSelect.value;
|
||||||
formData.append("client_specific_fields", JSON.stringify(finalSpecificFields));
|
formData.append("idroutine", routineId);
|
||||||
|
|
||||||
// Debug del FormData
|
|
||||||
console.log("FormData contents:");
|
|
||||||
for (let pair of formData.entries()) {
|
|
||||||
console.log(pair[0] + ': ' + pair[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("process_insert_template_xls.php", {
|
fetch("process_insert_template_xls.php", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -552,7 +362,6 @@
|
|||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log("Fetch response:", data);
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Successo!",
|
title: "Successo!",
|
||||||
@@ -572,7 +381,6 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error("Errore Fetch:", error);
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Errore!",
|
title: "Errore!",
|
||||||
text: "Si è verificato un errore imprevisto.",
|
text: "Si è verificato un errore imprevisto.",
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ if (!$iddatadb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("SELECT id, iddatadb, part_number, part_description FROM identification_parts WHERE iddatadb = :iddatadb ORDER BY part_number ASC");
|
$stmt = $pdo->prepare("SELECT id, iddatadb, part_number, part_description, idmatrice, note, dateexpiry FROM identification_parts WHERE iddatadb = :iddatadb ORDER BY part_number ASC");
|
||||||
$stmt->execute([':iddatadb' => $iddatadb]);
|
$stmt->execute([':iddatadb' => $iddatadb]);
|
||||||
$parts = $stmt->fetchAll();
|
$parts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
echo json_encode(['success' => true, 'parts' => $parts]);
|
echo json_encode(['success' => true, 'parts' => $parts]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
$idquotations = $_GET['idquotations'] ?? null;
|
||||||
|
|
||||||
|
if (!$idquotations) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID quotations mancante']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT id, idquotations, part_number, part_description FROM identification_parts WHERE idquotations = :idquotations ORDER BY part_number ASC");
|
||||||
|
$stmt->execute([':idquotations' => $idquotations]);
|
||||||
|
$parts = $stmt->fetchAll();
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'parts' => $parts]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
// load_photo_quotation.php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
$idquotations = isset($_GET['idquotations']) ? intval($_GET['idquotations']) : null;
|
||||||
|
|
||||||
|
if (!$idquotations) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID quotation mancante']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Seleziona le foto per il dato idquotations dalla tabella datadb_photos
|
||||||
|
$stmt = $pdo->prepare("SELECT id, file_path FROM datadb_photos WHERE idquotations = ?");
|
||||||
|
$stmt->execute([$idquotations]);
|
||||||
|
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($photos && count($photos) > 0) {
|
||||||
|
$photoPaths = array_map(function ($photo) {
|
||||||
|
return '../photostrf/' . $photo['file_path'];
|
||||||
|
}, $photos);
|
||||||
|
echo json_encode(['success' => true, 'photos' => $photoPaths]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Nessuna foto trovata']);
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
// Recupera l'ID dell'utente loggato
|
||||||
|
$user_id = $iduserlogin ?? 1;
|
||||||
|
|
||||||
|
if (!$user_id) {
|
||||||
|
echo json_encode(['success' => false, 'message' => "ID dell'utente autenticato mancante"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"SELECT DISTINCT q.*
|
||||||
|
FROM quotations q
|
||||||
|
INNER JOIN identification_parts ip
|
||||||
|
ON ip.idquotations = q.id
|
||||||
|
AND ip.iddatadb IS NULL
|
||||||
|
WHERE q.iduser = :iduser"
|
||||||
|
);
|
||||||
|
$stmt->execute([':iduser' => $user_id]);
|
||||||
|
$quotations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'quotations' => $quotations]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento delle quotations: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -97,6 +97,31 @@ if (!$template) {
|
|||||||
<ul id="associationsList" class="list-group border p-3"></ul>
|
<ul id="associationsList" class="list-group border p-3"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Default Values (Fixed fields) -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h5>Default Values (Fixed fields)</h5>
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">MoltiplicatorePrezzo (default)</label>
|
||||||
|
<select id="defaultMoltiplicatorePrezzo" class="form-select">
|
||||||
|
<option value="">Loading...</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">Loaded from API: get_moltiplicatoreprezzo.php</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label">ConsegnaRichiesta (default)</label>
|
||||||
|
<input type="date" id="defaultConsegnaRichiesta" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<button class="btn btn-success" id="saveDefaultsBtn">💾 Save defaults</button>
|
||||||
|
<span id="defaultsStatus" class="ms-2 text-muted"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Save Button -->
|
<!-- Save Button -->
|
||||||
<div class="mt-4 text-end">
|
<div class="mt-4 text-end">
|
||||||
<a href="templates_dashboard.php" class="btn btn-primary">⬅ Back to Template Dashboard</a>
|
<a href="templates_dashboard.php" class="btn btn-primary">⬅ Back to Template Dashboard</a>
|
||||||
@@ -273,7 +298,7 @@ if (!$template) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error loading table columns:', error));
|
.catch(error => console.error('Error loading table columns:', error));
|
||||||
*/
|
*/
|
||||||
/** =======================
|
/** =======================
|
||||||
* CARICAMENTO MAPPATURE GIÀ ESISTENTI
|
* CARICAMENTO MAPPATURE GIÀ ESISTENTI
|
||||||
* ======================= */
|
* ======================= */
|
||||||
@@ -441,6 +466,97 @@ if (!$template) {
|
|||||||
})
|
})
|
||||||
.catch(error => console.error("❌ Fetch error:", error));
|
.catch(error => console.error("❌ Fetch error:", error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** =======================
|
||||||
|
* DEFAULTS (Fixed fields)
|
||||||
|
* - stored in localStorage for now
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
const defaultsKey = "tpl_defaults_" + templateId;
|
||||||
|
|
||||||
|
function loadDefaultsFromLocal() {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(defaultsKey);
|
||||||
|
if (!raw) return;
|
||||||
|
const saved = JSON.parse(raw);
|
||||||
|
|
||||||
|
if (saved && typeof saved === "object") {
|
||||||
|
if (saved.moltiplicatore_prezzo_id !== undefined) {
|
||||||
|
document.getElementById('defaultMoltiplicatorePrezzo').value = saved.moltiplicatore_prezzo_id || "";
|
||||||
|
}
|
||||||
|
if (saved.consegna_richiesta !== undefined) {
|
||||||
|
document.getElementById('defaultConsegnaRichiesta').value = saved.consegna_richiesta || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("⚠️ Cannot parse saved defaults:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDefaultsToLocal() {
|
||||||
|
const moltiplicatoreId = document.getElementById('defaultMoltiplicatorePrezzo').value || "";
|
||||||
|
const consegna = document.getElementById('defaultConsegnaRichiesta').value || "";
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
moltiplicatore_prezzo_id: moltiplicatoreId,
|
||||||
|
consegna_richiesta: consegna
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorage.setItem(defaultsKey, JSON.stringify(payload));
|
||||||
|
|
||||||
|
const status = document.getElementById('defaultsStatus');
|
||||||
|
status.textContent = "✅ Defaults saved for this template (local)";
|
||||||
|
setTimeout(() => status.textContent = "", 2500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMoltiplicatoriPrezzo() {
|
||||||
|
const select = document.getElementById('defaultMoltiplicatorePrezzo');
|
||||||
|
select.innerHTML = `<option value="">-- Select --</option>`;
|
||||||
|
|
||||||
|
fetch('get_moltiplicatoreprezzo.php')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
// OData tipico: { value: [...] }
|
||||||
|
const rows = Array.isArray(data?.value) ? data.value : (Array.isArray(data) ? data : []);
|
||||||
|
if (!rows.length) {
|
||||||
|
select.innerHTML = `<option value="">(No data)</option>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.forEach(item => {
|
||||||
|
// ⚠️ Qui i nomi campi dipendono dal JSON reale:
|
||||||
|
// - id: item.Id / item.ID / item.idMoltiplicatorePrezzo
|
||||||
|
// - label: item.Descrizione / item.Nome / item.Codice
|
||||||
|
const id = item.IdMoltiplicatorePrezzo;
|
||||||
|
const label = `${item.Descrizione} (x${item.Fattore})`;
|
||||||
|
|
||||||
|
|
||||||
|
if (id === undefined || id === null) return;
|
||||||
|
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = String(id);
|
||||||
|
opt.textContent = String(label);
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
// dopo aver popolato, prova a rimettere il valore salvato
|
||||||
|
loadDefaultsFromLocal();
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error("❌ Error loading MoltiplicatorePrezzo:", err);
|
||||||
|
select.innerHTML = `<option value="">(Load error)</option>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
document.getElementById('saveDefaultsBtn').addEventListener('click', function() {
|
||||||
|
saveDefaultsToLocal();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Init
|
||||||
|
loadMoltiplicatoriPrezzo();
|
||||||
|
loadDefaultsFromLocal();
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,274 @@
|
|||||||
|
<!-- Modal per la gestione delle annotazioni -->
|
||||||
|
<div class="modal fade" id="annotationsModal" tabindex="-1" aria-labelledby="annotationsModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-xl" style="max-width: 90% !important; width: 90% !important;">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="annotationsModalLabel">Annotazioni per TRF: <span id="trfHeaderAnnotations"></span></h5>
|
||||||
|
|
||||||
|
<!-- SLIDER PER DIMENSIONE MARKER -->
|
||||||
|
<div style="display: flex; align-items: center; gap: 10px; margin-left: 20px;">
|
||||||
|
<label for="markerSizeSlider" style="margin: 0; font-size: 0.9rem; white-space: nowrap;">Dimensione marker:</label>
|
||||||
|
<input type="range" id="markerSizeSlider" min="16" max="48" value="16" step="2" style="width: 120px;">
|
||||||
|
<span id="markerSizeValue" style="font-weight: bold; min-width: 30px;">24px</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<!-- COLONNA SINISTRA RIDOTTA -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h6 style="margin: 0;">Elenco Parti</h6>
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<input type="checkbox" id="showMixPartsAnnotations" name="showMixPartsAnnotations" style="margin-right: 5px;">
|
||||||
|
<label for="showMixPartsAnnotations" style="font-size: 0.9rem;">Mix</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul id="partsListAnnotations" class="list-group" style="max-height: 500px; overflow-y: auto;"></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- COLONNA DESTRA PIÙ GRANDE -->
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h6>Foto del Campione</h6>
|
||||||
|
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
||||||
|
<div id="photoSelectorContainerAnnotations" style="display: none;"></div>
|
||||||
|
</div>
|
||||||
|
<div style="position: relative; width: 100%; min-height: 500px; border: 1px solid #ddd; border-radius: 4px; overflow: hidden;">
|
||||||
|
<img id="samplePhotoAnnotations" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
||||||
|
<canvas id="photoCanvasAnnotations" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
||||||
|
<canvas id="overlayCanvasAnnotations" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000;"></canvas>
|
||||||
|
<div id="descriptionListAnnotations" class="draggable-description" style="display: none;"></div>
|
||||||
|
<div id="markerContainerAnnotations"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="addDescriptionsBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Aggiungi Lista Descrizioni</button>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm" id="removeAnnotationsBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rimuovi Descrizioni</button>
|
||||||
|
<button type="button" class="btn btn-warning btn-sm" id="undoMarkerBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Undo Marker</button>
|
||||||
|
<button type="button" class="btn btn-success btn-sm" id="savePhotoBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Salva Foto con Nome</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="backToPartsBtnAnnotations" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Torna alle Parti</button>
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Chiudi</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#annotationsModal {
|
||||||
|
z-index: 1070 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#annotationsModal .modal-backdrop {
|
||||||
|
z-index: 1065 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#annotationsModal .modal-content {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .list-group-item {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .list-group-item:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .list-group-item.active {
|
||||||
|
background-color: #e9ecef;
|
||||||
|
border-color: #dee2e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-description {
|
||||||
|
position: absolute;
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 5px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
color: #000000;
|
||||||
|
cursor: move;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 1000;
|
||||||
|
min-width: 100px;
|
||||||
|
min-height: 50px;
|
||||||
|
overflow: visible;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-description.active-interaction {
|
||||||
|
border: 2px dashed #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-description div {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: #888;
|
||||||
|
cursor: se-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-marker {
|
||||||
|
position: absolute;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: #ffffff;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: move;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markerContainerAnnotations {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#savePhotoBtnAnnotations {
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#savePhotoBtnAnnotations.unsaved {
|
||||||
|
background-color: #dc3545 !important;
|
||||||
|
border-color: #dc3545 !important;
|
||||||
|
color: white !important;
|
||||||
|
animation: pulse 1.2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
box-shadow: 0 0 10px 15px rgba(220, 53, 69, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 0 0 rgba(220, 53, 69, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-picker-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: visible;
|
||||||
|
z-index: 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-picker {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 25px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
z-index: 2000;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-option {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 3px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-option:hover {
|
||||||
|
border: 2px solid #000;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-color {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin-left: 5px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-color:hover {
|
||||||
|
border: 2px solid #000;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.temp-alert {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stile per lo slider */
|
||||||
|
#markerSizeSlider {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #ddd;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markerSizeSlider::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #007bff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#markerSizeSlider::-moz-range-thumb {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #007bff;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .list-group-item.dragging {
|
||||||
|
opacity: 0.6;
|
||||||
|
background-color: #d1e7dd !important;
|
||||||
|
transform: rotate(3deg);
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsListAnnotations .placeholder {
|
||||||
|
background-color: #f8d7da !important;
|
||||||
|
border: 2px dashed #dc3545;
|
||||||
|
height: 40px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
|
||||||
+173
-31
@@ -1,4 +1,4 @@
|
|||||||
<!-- Modal -->
|
<!-- Modal modificato con pulsante per riconoscimento vocale, download e selezione matrici -->
|
||||||
<div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true">
|
<div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl" style="max-width: 80% !important; width: 80% !important;">
|
<div class="modal-dialog modal-xl" style="max-width: 80% !important; width: 80% !important;">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -9,39 +9,51 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6>Elenco Parti</h6>
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; min-width: 0;">
|
||||||
|
<h6 style="margin: 0; white-space: nowrap;">Elenco Parti</h6>
|
||||||
|
<div style="display: flex; align-items: center; min-width: 0;">
|
||||||
|
<select id="global-matrice" class="ms-2" style="width: 250px !important; min-width: 250px !important;">
|
||||||
|
</select>
|
||||||
|
<input type="checkbox" id="showMixParts" name="showMixParts" style="margin-right: 5px; margin-left: 10px;">
|
||||||
|
<label for="showMixParts" style="font-size: 0.9rem; margin-right: 10px;">Mix</label>
|
||||||
|
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rinumera Parti</button>
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-microphone"></i> Voce</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<ul id="partsList" class="list-group"></ul>
|
<ul id="partsList" class="list-group"></ul>
|
||||||
<table class="table table-striped table-sm mt-3" id="partsTable">
|
<table class="table table-striped table-sm mt-3" id="partsTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Num. Parte</th>
|
<th>Num. Parte</th>
|
||||||
<th>Descrizione Parte</th>
|
<th>Descrizione Parte</th>
|
||||||
<th>Azioni</th>
|
<th>Azioni</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="partsTableBody">
|
<tbody id="partsTableBody">
|
||||||
<tr data-part-id="new">
|
<tr data-part-id="new">
|
||||||
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
|
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
|
||||||
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione" style="width: 100%;"></td>
|
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione" style="width: 100%;"></td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
|
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
|
||||||
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
|
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
|
||||||
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
||||||
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
||||||
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6>Foto del Campione</h6>
|
<h6>Foto del Campione</h6>
|
||||||
<div id="photoSelectorContainer" style="display: none;">
|
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
||||||
<!-- Dropdown or buttons for photo selection will appear here -->
|
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
||||||
|
<div id="photoSelectorContainer" style="display: none;"></div>
|
||||||
</div>
|
</div>
|
||||||
<div style="position: relative; width: 100%; min-height: 400px;">
|
<div style="position: relative; width: 100%; min-height: 400px;">
|
||||||
<img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
<img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
|
||||||
<canvas id="photoCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
<canvas id="photoCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
|
||||||
|
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000;"></canvas>
|
||||||
<div id="descriptionList" class="draggable-description" style="display: none;"></div>
|
<div id="descriptionList" class="draggable-description" style="display: none;"></div>
|
||||||
<div id="markerContainer"></div>
|
<div id="markerContainer"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,7 +62,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-primary btn-sm" id="addDescriptionsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Aggiungi Lista Descrizioni</button>
|
<button type="button" class="btn btn-primary btn-sm" id="addDescriptionsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Aggiungi Lista Descrizioni</button>
|
||||||
<button type="button" class="btn btn-danger btn-sm" id="removeAnnotationsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rimuovi Annotazioni</button>
|
<button type="button" class="btn btn-danger btn-sm" id="removeAnnotationsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rimuovi Descrizioni</button>
|
||||||
|
<button type="button" class="btn btn-warning btn-sm" id="undoMarkerBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Undo Marker</button>
|
||||||
<button type="button" class="btn btn-success btn-sm" id="savePhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Salva Foto con Nome</button>
|
<button type="button" class="btn btn-success btn-sm" id="savePhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Salva Foto con Nome</button>
|
||||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Chiudi</button>
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Chiudi</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,6 +101,14 @@
|
|||||||
font-size: 0.6rem !important;
|
font-size: 0.6rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#partsModal {
|
||||||
|
z-index: 1060 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsModal .modal-backdrop {
|
||||||
|
z-index: 1055 !important;
|
||||||
|
}
|
||||||
|
|
||||||
#partsModal .modal-content {
|
#partsModal .modal-content {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
max-width: 100% !important;
|
max-width: 100% !important;
|
||||||
@@ -99,30 +120,58 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 5px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#partsList .list-group-item:hover {
|
#partsList .list-group-item:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#partsList input[type="color"] {
|
||||||
|
width: 30px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.draggable-description {
|
.draggable-description {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: rgba(255, 255, 255, 0.8);
|
background: rgba(255, 255, 255, 0.8);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
font-size: 10px;
|
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
min-width: 100px;
|
||||||
|
min-height: 50px;
|
||||||
|
overflow: visible;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-description.active-interaction {
|
||||||
|
border: 2px dashed #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-description div {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: #888;
|
||||||
|
cursor: se-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.draggable-marker {
|
.draggable-marker {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
background: rgba(255, 0, 0, 0.5);
|
|
||||||
border: 1px solid #ff0000;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -146,23 +195,116 @@
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ნორმალური Save ღილაკი */
|
|
||||||
#savePhotoBtn {
|
#savePhotoBtn {
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* დაუმახსოვრებელი ცვლილებები */
|
|
||||||
#savePhotoBtn.unsaved {
|
#savePhotoBtn.unsaved {
|
||||||
background-color: #dc3545 !important; /* წითელი */
|
background-color: #dc3545 !important;
|
||||||
border-color: #dc3545 !important;
|
border-color: #dc3545 !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
animation: pulse 1.2s infinite;
|
animation: pulse 1.2s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ლამაზი პულსაცია */
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); }
|
0% {
|
||||||
70% { box-shadow: 0 0 10px 15px rgba(220, 53, 69, 0); }
|
box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7);
|
||||||
100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
box-shadow: 0 0 10px 15px rgba(220, 53, 69, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 0 0 rgba(220, 53, 69, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-picker-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-picker {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 25px;
|
||||||
|
left: 0;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
z-index: 1002;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-option {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 3px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-option:hover {
|
||||||
|
border: 2px solid #000;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stili per Select2 in #partsList e #global-matrice */
|
||||||
|
#partsList .select2-container,
|
||||||
|
.select2-container--default #global-matrice {
|
||||||
|
width: 250px !important;
|
||||||
|
min-width: 250px !important;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsList .select2-selection--single,
|
||||||
|
.select2-container--default #global-matrice .select2-selection--single {
|
||||||
|
height: 26px !important;
|
||||||
|
padding: 0.2rem 0.5rem !important;
|
||||||
|
font-size: 0.9rem !important;
|
||||||
|
border: 1px solid #ced4da !important;
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsList .select2-selection__rendered,
|
||||||
|
.select2-container--default #global-matrice .select2-selection__rendered {
|
||||||
|
line-height: 24px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsList .select2-selection__arrow,
|
||||||
|
.select2-container--default #global-matrice .select2-selection__arrow {
|
||||||
|
height: 26px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsList .save-status,
|
||||||
|
#partsList .save-loading {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--open .select2-dropdown {
|
||||||
|
z-index: 1051 !important;
|
||||||
|
border: 1px solid #aaa !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
background: white !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
max-height: 200px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||||
|
width: 100% !important;
|
||||||
|
padding: 0.2rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .part-matrice,
|
||||||
|
.select2-container--default #global-matrice {
|
||||||
|
width: 250px !important;
|
||||||
|
min-width: 250px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -0,0 +1,496 @@
|
|||||||
|
<div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-xl" style="max-width: 80% !important;">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="partsModalLabel">Parti per TRF: <span id="trfHeader"></span></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row parts-row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<!-- Prima riga: Elenco Parti, Rinumera, Voce -->
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h6 style="margin: 0;">Elenco Parti</h6>
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Rinumera Parti</button>
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-microphone"></i> Voce</button>
|
||||||
|
<button type="button" class="btn btn-info btn-sm ms-2 d-none" id="quotationeBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">Add Quotation</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm ms-2" id="showHideImageBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
|
<i class="fas fa-eye-slash" style="font-size: 0.8rem;"></i>
|
||||||
|
<i class="fas fa-image ms-1" style="font-size: 0.8rem;"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Seconda riga: +, M, MacroMatrice, Matrice globale, Propaga -->
|
||||||
|
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
||||||
|
<button type="button" class="btn btn-success btn-sm add-row-global" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 5px;"><i class="fas fa-plus fa-xs"></i></button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm add-mix-global" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 10px;">M</button>
|
||||||
|
<select id="macro-matrice-filter" class="form-control form-control-sm ms-2" style="width: 200px !important; min-width: 200px !important; margin-right: 10px;">
|
||||||
|
<option value="">Tutte le MacroMatrici</option>
|
||||||
|
</select>
|
||||||
|
<select id="global-matrice" class="form-control form-control-sm" style="width: 350px !important; margin-right: 10px;"></select>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm propagate-all-btn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;"><i class="fas fa-arrow-right fa-xs"></i> Propaga a tutte</button>
|
||||||
|
</div>
|
||||||
|
<table class="table table-striped table-sm" id="partsTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 80px;">Numero</th>
|
||||||
|
<th>Descrizione</th>
|
||||||
|
<th style="width: 200px;">Matrice</th>
|
||||||
|
<th style="width: 150px;">
|
||||||
|
<input type="date" class="form-control form-control-sm propagate-date-input" style="width: 130px; margin-left: 5px; display: inline-block;" title="Propaga data a tutte le parti">
|
||||||
|
</th>
|
||||||
|
<th style="width: 200px;">
|
||||||
|
<button type="button" class="btn btn-light btn-sm propagate-note-btn" style="padding: 0.2rem 0.4rem; font-size: 0.9rem; margin-left: 5px;" title="Propaga nota a tutte le parti">
|
||||||
|
<i class="fas fa-sticky-note"></i>
|
||||||
|
</button>
|
||||||
|
Azioni
|
||||||
|
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="partsTableBody">
|
||||||
|
<tr data-part-id="new">
|
||||||
|
<td><input type="number" class="form-control form-control-sm part-number" value="1" style="width: 80px;"></td>
|
||||||
|
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione"></td>
|
||||||
|
<td>
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm propagate-matrice-btn" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; margin-right: 3px;"><i class="fas fa-arrow-right fa-xs"></i></button>
|
||||||
|
<select class="part-matrice form-control form-control-sm" style="width: 150px;"></select>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td><input type="date" class="form-control form-control-sm part-dateexpiry" style="width: 130px;"></td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-light btn-sm note-btn" style="padding: 0.2rem 0.4rem; font-size: 0.9rem;" title="Aggiungi/Modifica nota"><i class="fas fa-sticky-note"></i></button>
|
||||||
|
<button type="button" class="btn btn-warning btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M+</button>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
|
||||||
|
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
|
||||||
|
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h6>Foto del Campione</h6>
|
||||||
|
<div style="display: flex; align-items: center; margin-bottom: 10px;">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i></button>
|
||||||
|
<div id="photoSelectorContainer" style="display: none;"></div>
|
||||||
|
</div>
|
||||||
|
<div style="position: relative; width: 100%; min-height: 400px;">
|
||||||
|
<img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 400px; object-fit: contain;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="openAnnotationsBtn">Apri Annotazioni</button>
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Chiudi</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modale per la nota -->
|
||||||
|
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-md">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="noteModalLabel">Nota per Parte</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<textarea class="form-control part-note" rows="5" placeholder="Inserisci una nota"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm save-note-btn">Salva</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="commonNoteModal" tabindex="-1" aria-labelledby="commonNoteModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="commonNoteModalLabel">Nota comune per tutte le parti</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<textarea class="form-control part-note" rows="4" placeholder="Inserisci nota comune"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Chiudi</button>
|
||||||
|
<button type="button" class="btn btn-primary save-common-note-btn">Salva</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modale di conferma per l'eliminazione -->
|
||||||
|
<div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-labelledby="confirmDeleteModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="confirmDeleteModalLabel">Conferma Eliminazione</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Sei sicuro di voler eliminare questa parte?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm" id="confirmDeleteBtn">Elimina</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Finestra modale "Aggiungi preventivo" -->
|
||||||
|
<div class="modal fade" id="addQuotationModal" tabindex="-1" aria-labelledby="addQuotationModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-md">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="addQuotationModalLabel">Choose a quotation</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<select id="addQuotationSelect" class="form-control form-control-sm" style="width: 100% !important; min-width: 100% !important"></select>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-primary btn-sm" id="addQuotationBtn">Confirm</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* --- Base --- */
|
||||||
|
#partsModal {
|
||||||
|
z-index: 1060 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsModal .modal-backdrop {
|
||||||
|
z-index: 1055 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsModal .modal-content {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#addQuotationModal {
|
||||||
|
z-index: 1060 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#addQuotationModal .modal-backdrop {
|
||||||
|
z-index: 1055 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tabelle */
|
||||||
|
#partsTable tr {
|
||||||
|
display: table-row !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable tr:hover {
|
||||||
|
background: #f5f5f5
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td,
|
||||||
|
#partsTable th {
|
||||||
|
padding: .2rem;
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable input,
|
||||||
|
#partsTable select {
|
||||||
|
height: 24px;
|
||||||
|
padding: .1rem .3rem
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable button {
|
||||||
|
padding: .1rem .3rem;
|
||||||
|
margin: 0 2px
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable i {
|
||||||
|
font-size: .6rem !important
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Larghezze fisse header --- */
|
||||||
|
/* MacroMatrici = 250px */
|
||||||
|
#macro-matrice-filter {
|
||||||
|
width: 250px !important;
|
||||||
|
min-width: 250px !important;
|
||||||
|
max-width: 250px !important;
|
||||||
|
flex: 0 0 250px !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#macro-matrice-filter.select2-hidden-accessible+.select2 {
|
||||||
|
width: 250px !important;
|
||||||
|
min-width: 250px !important;
|
||||||
|
max-width: 250px !important;
|
||||||
|
flex: 0 0 250px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#macro-matrice-filter.select2-hidden-accessible+.select2 .select2-selection__rendered {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Matrice globale = 450px */
|
||||||
|
#global-matrice {
|
||||||
|
width: 450px !important;
|
||||||
|
min-width: 450px !important;
|
||||||
|
max-width: 450px !important;
|
||||||
|
flex: 0 0 450px !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#global-matrice.select2-hidden-accessible+.select2 {
|
||||||
|
width: 450px !important;
|
||||||
|
min-width: 450px !important;
|
||||||
|
max-width: 450px !important;
|
||||||
|
flex: 0 0 450px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#global-matrice.select2-hidden-accessible+.select2 .select2-selection__rendered {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select delle righe (colonna Matrice) = 150px */
|
||||||
|
.part-matrice {
|
||||||
|
width: 300px !important;
|
||||||
|
min-width: 300px !important;
|
||||||
|
max-width: 300px !important;
|
||||||
|
flex: 0 0 300px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part-matrice.select2-hidden-accessible+.select2 {
|
||||||
|
width: 300px !important;
|
||||||
|
min-width: 300px !important;
|
||||||
|
max-width: 300px !important;
|
||||||
|
flex: 0 0 300px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Colonna Descrizione (2ª colonna) = 420px */
|
||||||
|
#partsTable th:nth-child(2),
|
||||||
|
#partsTable td:nth-child(2) {
|
||||||
|
width: 350 !important;
|
||||||
|
min-width: 350px !important;
|
||||||
|
max-width: 350px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsTable td:nth-child(2) .part-description {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aspetto Select2 */
|
||||||
|
.select2-container--default .select2-selection--single {
|
||||||
|
height: 24px !important;
|
||||||
|
padding: .1rem .3rem !important;
|
||||||
|
font-size: .8rem !important;
|
||||||
|
border: 1px solid #ced4da !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--default .select2-selection__arrow {
|
||||||
|
height: 24px !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container--open .select2-dropdown {
|
||||||
|
z-index: 1061 !important;
|
||||||
|
border: 1px solid #aaa !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
background: #fff !important;
|
||||||
|
max-height: 200px !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evita stretching del flex nella riga dei filtri */
|
||||||
|
#partsModal .modal-body>.row .col-md-9>div[style*="display: flex"]>* {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Altri modali e pulsanti */
|
||||||
|
.propagate-matrice-btn,
|
||||||
|
.propagate-all-btn {
|
||||||
|
padding: .1rem .3rem !important;
|
||||||
|
font-size: .8rem !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-status,
|
||||||
|
.save-loading {
|
||||||
|
margin-left: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
#confirmDeleteModal {
|
||||||
|
z-index: 1070 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#confirmDeleteModal .modal-backdrop {
|
||||||
|
z-index: 1065 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-btn {
|
||||||
|
padding: .2rem .4rem !important;
|
||||||
|
font-size: .9rem !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-btn.has-note {
|
||||||
|
color: #dc3545 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#noteModal {
|
||||||
|
z-index: 1090 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#noteModal .modal-backdrop {
|
||||||
|
z-index: 1085 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#noteModal .modal-dialog {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1090 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#noteModal textarea,
|
||||||
|
#commonNoteModal textarea {
|
||||||
|
resize: vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
#commonNoteModal {
|
||||||
|
z-index: 1095 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#commonNoteModal .modal-backdrop {
|
||||||
|
z-index: 1090 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#commonNoteModal .modal-dialog {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1095 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evidenza salvataggio riga nel parts table */
|
||||||
|
/* Aumenta la specificità per le classi di flash */
|
||||||
|
table#partsTable tr.row-saving {
|
||||||
|
background-color: #f0ad4e !important;
|
||||||
|
/* Arancione per salvataggio in corso */
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
table#partsTable tr.row-success {
|
||||||
|
background-color: #5cb85c !important;
|
||||||
|
/* Verde per successo */
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
table#partsTable tr.row-error {
|
||||||
|
background-color: #d9534f !important;
|
||||||
|
/* Rosso per errore */
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stato base: nascosti (verrà sovrascritto dallo style inline di jQuery) */
|
||||||
|
#partsModal .save-loading,
|
||||||
|
#partsModal .save-status {
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quando NON sono nascosti via style inline (jQuery .show()), forzali a inline-flex */
|
||||||
|
#partsModal .save-loading:not([style*="display: none"]),
|
||||||
|
#partsModal .save-status:not([style*="display: none"]) {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading (giallo) */
|
||||||
|
/* Loading (giallo) */
|
||||||
|
#partsModal .save-loading {
|
||||||
|
background: #ffd753ff;
|
||||||
|
border: 1px solid #ffd042ff;
|
||||||
|
color: #111;
|
||||||
|
/* testo nero */
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsModal .save-loading i {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icona nera */
|
||||||
|
|
||||||
|
#partsModal .save-loading::after {
|
||||||
|
content: " Salvataggio…";
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Salvato (verde) */
|
||||||
|
#partsModal .save-status {
|
||||||
|
background: #5dff83ff;
|
||||||
|
border: 1px solid #4effafff;
|
||||||
|
color: #111;
|
||||||
|
/* testo nero */
|
||||||
|
}
|
||||||
|
|
||||||
|
#partsModal .save-status i {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icona nera */
|
||||||
|
#partsModal .save-status::after {
|
||||||
|
content: " Salvato";
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animazioni */
|
||||||
|
@keyframes pulse {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: .9
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.05);
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop {
|
||||||
|
0% {
|
||||||
|
transform: scale(.85);
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* rosso */
|
||||||
|
</style>
|
||||||
+1625
-452
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+738
-107
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
// photos_popup.php
|
// photos_popup.php
|
||||||
include('include/headscript.php');
|
include('include/headscript.php');
|
||||||
|
// Includi Fabric.js solo per questa pagina
|
||||||
|
?>
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
|
||||||
|
|
||||||
|
<?php
|
||||||
// Includi l'autoloader di Composer
|
// Includi l'autoloader di Composer
|
||||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||||
|
|
||||||
@@ -11,70 +17,131 @@ use Endroid\QrCode\QrCode;
|
|||||||
use Endroid\QrCode\RoundBlockSizeMode;
|
use Endroid\QrCode\RoundBlockSizeMode;
|
||||||
use Endroid\QrCode\Writer\PngWriter;
|
use Endroid\QrCode\Writer\PngWriter;
|
||||||
|
|
||||||
|
// Abilita logging per debug
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/photos_popup_debug.log');
|
||||||
|
|
||||||
|
// Log iniziale
|
||||||
|
error_log("Richiesta a photos_popup.php: " . print_r($_GET, true));
|
||||||
|
|
||||||
// Carica le variabili d'ambiente
|
// Carica le variabili d'ambiente
|
||||||
try {
|
try {
|
||||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../');
|
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../');
|
||||||
$dotenv->load();
|
$dotenv->load();
|
||||||
error_log("File .env caricato correttamente da " . __DIR__ . '/../../.env');
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("Errore nel caricamento del file .env: " . $e->getMessage());
|
error_log("Errore nel caricamento del file .env: " . $e->getMessage());
|
||||||
echo json_encode(['error' => 'Errore nel caricamento del file di configurazione']);
|
?>
|
||||||
|
<div class="popup-content">
|
||||||
|
<p>Errore: Impossibile caricare il file di configurazione.</p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifica che BASE_URL sia definito
|
// Verifica che BASE_URL sia definito
|
||||||
if (!isset($_ENV['BASE_URL'])) {
|
if (!isset($_ENV['BASE_URL'])) {
|
||||||
error_log("Errore: la variabile BASE_URL non è definita nel file .env");
|
error_log("Errore: la variabile BASE_URL non è definita nel file .env");
|
||||||
echo json_encode(['error' => 'Variabile BASE_URL non definita']);
|
?>
|
||||||
|
<div class="popup-content">
|
||||||
|
<p>Errore: Variabile BASE_URL non definita.</p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Verifica che l'iddatadb sia stato passato
|
// Verifica che almeno uno degli ID sia passato
|
||||||
if (!isset($_GET['iddatadb']) || empty($_GET['iddatadb'])) {
|
$iddatadb = isset($_GET['iddatadb']) && !empty($_GET['iddatadb']) ? intval($_GET['iddatadb']) : null;
|
||||||
echo json_encode(['error' => 'ID riga non fornito']);
|
$idquotations = isset($_GET['idquotations']) && !empty($_GET['idquotations']) ? intval($_GET['idquotations']) : null;
|
||||||
|
|
||||||
|
if (!$iddatadb && !$idquotations) {
|
||||||
|
error_log("Errore: ID riga o ID quotations non fornito");
|
||||||
|
?>
|
||||||
|
<div class="popup-content">
|
||||||
|
<p>Errore: ID riga o ID quotations non fornito.</p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$iddatadb = intval($_GET['iddatadb']);
|
if ($iddatadb && $idquotations) {
|
||||||
|
error_log("Errore: Non è possibile specificare sia iddatadb che idquotations");
|
||||||
// Recupera i dettagli della riga (idriga e sample_code)
|
?>
|
||||||
$stmt = $pdo->prepare("SELECT iddatadb, sample_code FROM datadb WHERE iddatadb = ?");
|
<div class="popup-content">
|
||||||
$stmt->execute([$iddatadb]);
|
<p>Errore: Non è possibile specificare sia iddatadb che idquotations.</p>
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
</div>
|
||||||
|
<?php
|
||||||
if (!$row) {
|
|
||||||
echo json_encode(['error' => 'Riga non trovata']);
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$idriga = $row['iddatadb'];
|
// Determina quale ID e tabella usare
|
||||||
$sampleCode = $row['sample_code'] ?? 'Non disponibile';
|
$paramName = $iddatadb ? 'iddatadb' : 'id'; // Usa 'id' per quotations
|
||||||
|
$paramValue = $iddatadb ?: $idquotations;
|
||||||
|
$table = $iddatadb ? 'datadb' : 'quotations';
|
||||||
|
$field = $iddatadb ? 'sample_code' : 'description'; // Usa 'description' per quotations
|
||||||
|
$photoTable = 'datadb_photos'; // Usa sempre datadb_photos
|
||||||
|
$photoParamName = $iddatadb ? 'iddatadb' : 'idquotations'; // Usa 'idquotations' per datadb_photos
|
||||||
|
|
||||||
|
// Recupera i dettagli della riga
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT {$paramName}, {$field} FROM {$table} WHERE {$paramName} = ?");
|
||||||
|
$stmt->execute([$paramValue]);
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
error_log("Errore: Riga non trovata per {$paramName} = {$paramValue}");
|
||||||
|
?>
|
||||||
|
<div class="popup-content">
|
||||||
|
<p>Errore: Riga non trovata.</p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Errore query dettagli riga: " . $e->getMessage());
|
||||||
|
?>
|
||||||
|
<div class="popup-content">
|
||||||
|
<p>Errore: Impossibile recuperare i dettagli della riga.</p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = $row[$paramName];
|
||||||
|
$code = $row[$field] ?? 'Non disponibile';
|
||||||
|
|
||||||
// Recupera le foto associate alla riga
|
// Recupera le foto associate alla riga
|
||||||
$stmt = $pdo->prepare("SELECT id, file_path, file_name, description, uploaded_at FROM datadb_photos WHERE iddatadb = ? ORDER BY uploaded_at DESC");
|
try {
|
||||||
$stmt->execute([$iddatadb]);
|
$stmt = $pdo->prepare("SELECT id, file_path, file_name, description, uploaded_at FROM {$photoTable} WHERE {$photoParamName} = ? ORDER BY uploaded_at DESC");
|
||||||
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$stmt->execute([$paramValue]);
|
||||||
|
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Errore query foto: " . $e->getMessage());
|
||||||
|
$photos = []; // Imposta array vuoto in caso di errore
|
||||||
|
}
|
||||||
|
|
||||||
// Definisci il percorso base per le foto
|
// Definisci il percorso base per le foto
|
||||||
$photoBasePath = '../photostrf/';
|
$photoBasePath = '../photostrf/';
|
||||||
|
|
||||||
// Usa la variabile d'ambiente BASE_URL
|
// Usa la variabile d'ambiente BASE_URL
|
||||||
$baseUrl = rtrim($_ENV['BASE_URL'], '/'); // Rimuove eventuali slash finali
|
$baseUrl = rtrim($_ENV['BASE_URL'], '/');
|
||||||
$uploadUrl = $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb;
|
$uploadUrl = $iddatadb
|
||||||
|
? $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb
|
||||||
|
: $baseUrl . "/upload_photos_mobile.php?idquotations=" . $idquotations;
|
||||||
|
|
||||||
// Genera il QR code con endroid/qr-code 6.0.6
|
// Genera il QR code con endroid/qr-code 6.0.6
|
||||||
$qrCodeDir = '../photostrf/qrcodes/';
|
$qrCodeDir = '../photostrf/qrcodes/';
|
||||||
if (!is_dir($qrCodeDir)) {
|
if (!is_dir($qrCodeDir)) {
|
||||||
mkdir($qrCodeDir, 0755, true);
|
mkdir($qrCodeDir, 0755, true);
|
||||||
}
|
}
|
||||||
$qrCodeFile = $qrCodeDir . "qrcode_{$iddatadb}.png";
|
$qrCodeFile = $qrCodeDir . "qrcode_{$id}.png";
|
||||||
|
|
||||||
$writer = new PngWriter();
|
$writer = new PngWriter();
|
||||||
|
|
||||||
// Crea il QR code usando il costruttore
|
|
||||||
$qrCode = new QrCode(
|
$qrCode = new QrCode(
|
||||||
data: $uploadUrl,
|
data: $uploadUrl,
|
||||||
encoding: new Encoding('UTF-8'),
|
encoding: new Encoding('UTF-8'),
|
||||||
@@ -98,13 +165,13 @@ $result->saveToFile($qrCodeFile);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h3>Manage Photos</h3>
|
<h3>Manage Photos</h3>
|
||||||
<p><strong>ID Row:</strong> <?= htmlspecialchars($idriga) ?></p>
|
<p><strong>ID:</strong> <?= htmlspecialchars($id) ?></p>
|
||||||
<p><strong>Sample Code:</strong> <?= htmlspecialchars($sampleCode) ?></p>
|
<p><strong>Code:</strong> <?= htmlspecialchars($code) ?></p>
|
||||||
|
|
||||||
<!-- QR Code per il caricamento da mobile -->
|
<!-- QR Code per il caricamento da mobile -->
|
||||||
<div style="text-align: center; margin-bottom: 20px;">
|
<div style="text-align: center; margin-bottom: 20px;">
|
||||||
<p>Scan the QR Code with the mobile to take photo with camera:</p>
|
<p>Scan the QR Code with the mobile to take photo with camera:</p>
|
||||||
<img src="../photostrf/qrcodes/qrcode_<?= $iddatadb ?>.png" alt="QR Code" style="max-width: 150px;">
|
<img src="../photostrf/qrcodes/qrcode_<?= htmlspecialchars($id) ?>.png" alt="QR Code" style="max-width: 150px;">
|
||||||
<p style="margin-top: 10px;">
|
<p style="margin-top: 10px;">
|
||||||
<a href="<?= htmlspecialchars($uploadUrl) ?>" target="_blank"><?= htmlspecialchars($uploadUrl) ?></a>
|
<a href="<?= htmlspecialchars($uploadUrl) ?>" target="_blank"><?= htmlspecialchars($uploadUrl) ?></a>
|
||||||
</p>
|
</p>
|
||||||
@@ -116,7 +183,6 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
|
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
<!-- Area per la webcam -->
|
<!-- Area per la webcam -->
|
||||||
<!-- Area per la webcam -->
|
|
||||||
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
|
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
|
||||||
<p>Webcam Preview</p>
|
<p>Webcam Preview</p>
|
||||||
<select id="webcamSelect" style="margin-bottom: 10px; padding: 5px;">
|
<select id="webcamSelect" style="margin-bottom: 10px; padding: 5px;">
|
||||||
@@ -128,10 +194,11 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
|
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button> <!-- Elenco delle foto -->
|
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button>
|
||||||
|
<!-- Elenco delle foto -->
|
||||||
<div id="photosList">
|
<div id="photosList">
|
||||||
<?php if (empty($photos)): ?>
|
<?php if (empty($photos)): ?>
|
||||||
<p>No Photos present.</p>
|
<p>Nessuna foto presente.</p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?php foreach ($photos as $photo): ?>
|
<?php foreach ($photos as $photo): ?>
|
||||||
<?php
|
<?php
|
||||||
@@ -156,6 +223,8 @@ $result->saveToFile($qrCodeFile);
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
<!-- Bottone Crea Collage -->
|
||||||
|
<button id="createCollageBtn" style="padding: 10px 20px; background: #ffc107; color: white; border: none; cursor: pointer; margin-top: 20px;">Crea Collage</button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -164,6 +233,52 @@ $result->saveToFile($qrCodeFile);
|
|||||||
<span class="image-modal-close">×</span>
|
<span class="image-modal-close">×</span>
|
||||||
<img id="enlargedImage" class="image-modal-content" src="" alt="Immagine ingrandita">
|
<img id="enlargedImage" class="image-modal-content" src="" alt="Immagine ingrandita">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modale per collage -->
|
||||||
|
<div id="collageModal" class="modal" style="display: none; position: fixed; z-index: 1002; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.8);">
|
||||||
|
<div class="modal-content" style="background: white; margin: 5% auto; padding: 20px; width: 80%; max-width: 1200px; position: relative;">
|
||||||
|
<span class="close-collage" style="position: absolute; top: 10px; right: 20px; font-size: 30px; font-weight: bold; color: #333; cursor: pointer; z-index: 1003; background: #fff; padding: 5px 10px; border-radius: 50%;">×</span>
|
||||||
|
<h3>Crea Collage</h3>
|
||||||
|
|
||||||
|
<!-- Lista foto selezionabili -->
|
||||||
|
<div id="collagePhotoList" style="max-height: 200px; overflow-y: auto; margin-bottom: 20px;">
|
||||||
|
<?php foreach ($photos as $photo): ?>
|
||||||
|
<div style="display: inline-block; margin: 10px;">
|
||||||
|
<input type="checkbox" class="photo-checkbox" data-path="../photostrf/<?= htmlspecialchars($photo['file_path']) ?>">
|
||||||
|
<img src="../photostrf/<?= htmlspecialchars($photo['file_path']) ?>" alt="" style="width: 80px; height: 80px;">
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottone per aggiungere selezionate al canvas -->
|
||||||
|
<button id="addToCanvasBtn">Aggiungi Selezionate al Canvas</button>
|
||||||
|
|
||||||
|
<!-- Canvas per editing -->
|
||||||
|
<canvas id="collageCanvas" width="960" height="720" style="border: 1px solid #ccc; margin-top: 20px;"></canvas>
|
||||||
|
|
||||||
|
<!-- Pannello dei livelli -->
|
||||||
|
<div id="layersPanel" style="width: 120px; max-height: 600px; overflow-y: auto; background: #f8f9fa; padding: 10px; position: absolute; right: 0; top: 60px;">
|
||||||
|
<h4 style="margin: 0 0 10px 0; font-size: 16px;">Livelli</h4>
|
||||||
|
<ul id="layersList" style="list-style: none; padding: 0;"></ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottoni azioni -->
|
||||||
|
<div style="margin-top: 20px; display: flex; flex-wrap: wrap; gap: 5px;">
|
||||||
|
<button id="saveCollageBtn" title="Salva il collage"><i class="fas fa-save"></i></button>
|
||||||
|
<button id="bringToFrontBtn" title="Porta in primo piano"><i class="fas fa-arrow-up"></i></button>
|
||||||
|
<button id="sendToBackBtn" title="Manda in fondo"><i class="fas fa-arrow-down"></i></button>
|
||||||
|
<button id="bringForwardBtn" title="Sposta avanti di un livello"><i class="fas fa-arrow-circle-up"></i></button>
|
||||||
|
<button id="sendBackwardBtn" title="Sposta indietro di un livello"><i class="fas fa-arrow-circle-down"></i></button>
|
||||||
|
<button id="cropImageBtn" title="Ritaglia immagine selezionata" disabled><i class="fas fa-crop"></i></button>
|
||||||
|
<button id="applyCropBtn" title="Applica ritaglio" disabled><i class="fas fa-crop"></i> Applica</button>
|
||||||
|
<button id="cancelCropBtn" title="Annulla ritaglio" disabled><i class="fas fa-crop"></i> Annulla</button>
|
||||||
|
<button id="removeBackgroundBtn" title="Rimuovi sfondo immagine selezionata" disabled><i class="fas fa-eraser"></i> Rimuovi Sfondo</button>
|
||||||
|
<button id="removeImageBtn" title="Rimuovi immagine selezionata" disabled><i class="fas fa-trash-alt"></i> Rimuovi</button>
|
||||||
|
<button id="undoBtn" title="Annulla ultima azione" disabled><i class="fas fa-undo"></i></button>
|
||||||
|
<p id="backgroundRemovalInstruction" style="display: none; color: #007bff;">Clicca sull'immagine per selezionare il colore dello sfondo da rimuovere</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -243,4 +358,71 @@ $result->saveToFile($qrCodeFile);
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stile per i pulsanti del modale collage */
|
||||||
|
#collageModal button {
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin: 5px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#saveCollageBtn {
|
||||||
|
background: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bringToFrontBtn,
|
||||||
|
#sendToBackBtn,
|
||||||
|
#bringForwardBtn,
|
||||||
|
#sendBackwardBtn {
|
||||||
|
background: #007bff;
|
||||||
|
color: white;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cropImageBtn,
|
||||||
|
#applyCropBtn,
|
||||||
|
#cancelCropBtn,
|
||||||
|
#removeBackgroundBtn,
|
||||||
|
#removeImageBtn,
|
||||||
|
#undoBtn {
|
||||||
|
background: #ffc107;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#collageModal button:disabled {
|
||||||
|
background: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#collageModal button i {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stile per il pannello dei livelli */
|
||||||
|
#layersPanel {
|
||||||
|
z-index: 1002;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layersPanel li {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layersPanel img {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
cursor: pointer;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layersPanel img:hover {
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -18,9 +18,13 @@ try {
|
|||||||
$target_table = trim($_POST['target_table']);
|
$target_table = trim($_POST['target_table']);
|
||||||
$idclient = intval($_POST['client_id'] ?? 0); // Usa client_id dal form
|
$idclient = intval($_POST['client_id'] ?? 0); // Usa client_id dal form
|
||||||
$clientname = trim($_POST['client_name'] ?? ''); // Usa client_name dal form
|
$clientname = trim($_POST['client_name'] ?? ''); // Usa client_name dal form
|
||||||
$client_specific_fields = trim($_POST['client_specific_fields'] ?? '{}'); // Recupera il JSON dei campi specifici
|
|
||||||
$idschema = intval($_POST['idschema'] ?? 0); // Nuovo campo
|
$idschema = intval($_POST['idschema'] ?? 0); // Nuovo campo
|
||||||
$schemamaname = trim($_POST['schemamaname'] ?? ''); // Nuovo campo
|
$schemaname = trim($_POST['schemaname'] ?? ''); // Corretto da schemamaname
|
||||||
|
$idroutine = isset($_POST['idroutine']) && $_POST['idroutine'] !== '' ? intval($_POST['idroutine']) : null; // Aggiunto idroutine
|
||||||
|
$button_size = trim($_POST['button_size'] ?? 'medium'); // Nuovo campo
|
||||||
|
$button_bg_color = trim($_POST['button_bg_color'] ?? '#007bff'); // Nuovo campo
|
||||||
|
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff'); // Nuovo campo
|
||||||
|
$button_label = trim($_POST['button_label'] ?? 'Click Me'); // Nuovo campo
|
||||||
|
|
||||||
// Controllo sui campi obbligatori
|
// Controllo sui campi obbligatori
|
||||||
if (empty($id) || empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idschema <= 0) {
|
if (empty($id) || empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idschema <= 0) {
|
||||||
@@ -32,20 +36,16 @@ try {
|
|||||||
throw new Exception("Please select a valid client.");
|
throw new Exception("Please select a valid client.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validazione opzionale del JSON (per sicurezza)
|
|
||||||
$decoded_fields = json_decode($client_specific_fields, true);
|
|
||||||
if (json_last_error() !== JSON_ERROR_NONE && $client_specific_fields !== '{}') {
|
|
||||||
throw new Exception("Invalid JSON format for client-specific fields.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connessione al database
|
// Connessione al database
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Aggiorna il database, includendo idschema e schemaname
|
// Aggiorna il database, includendo i nuovi campi
|
||||||
$stmt = $pdo->prepare("UPDATE excel_templates
|
$stmt = $pdo->prepare("UPDATE excel_templates
|
||||||
SET name = ?, header_row = ?, start_column = ?, description = ?, target_table = ?,
|
SET name = ?, header_row = ?, start_column = ?, description = ?, target_table = ?,
|
||||||
idclient = ?, clientname = ?, client_specific_fields = ?, schemaname = ?, idschema = ?, updated_at = NOW()
|
idclient = ?, clientname = ?, schemaname = ?, idschema = ?, idroutine = ?,
|
||||||
|
button_size = ?, button_bg_color = ?, button_text_color = ?, button_label = ?,
|
||||||
|
updated_at = NOW()
|
||||||
WHERE id = ?");
|
WHERE id = ?");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$name,
|
$name,
|
||||||
@@ -55,9 +55,13 @@ try {
|
|||||||
$target_table,
|
$target_table,
|
||||||
$idclient,
|
$idclient,
|
||||||
$clientname,
|
$clientname,
|
||||||
$client_specific_fields,
|
$schemaname,
|
||||||
$schemamaname,
|
|
||||||
$idschema,
|
$idschema,
|
||||||
|
$idroutine,
|
||||||
|
$button_size,
|
||||||
|
$button_bg_color,
|
||||||
|
$button_text_color,
|
||||||
|
$button_label,
|
||||||
$id
|
$id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
// Sopprime eventuali output di errori (li logghiamo invece di mostrarli)
|
// Sopprime eventuali output di errori (li logghiamo invece di mostrarli)
|
||||||
ob_start();
|
ob_start();
|
||||||
ini_set('display_errors', 0); // Disattiva l'output degli errori a schermo
|
ini_set('display_errors', 0);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
// Inizia la sessione
|
// Inizia la sessione
|
||||||
@@ -9,9 +9,9 @@ session_start();
|
|||||||
|
|
||||||
// Includi PHPSpreadsheet e la classe DBHandler
|
// Includi PHPSpreadsheet e la classe DBHandler
|
||||||
require_once '../../vendor/autoload.php';
|
require_once '../../vendor/autoload.php';
|
||||||
require_once __DIR__ . '/class/db-functions.php'; // Assumo che DBHandlerSelect sia qui
|
require_once __DIR__ . '/class/db-functions.php';
|
||||||
|
|
||||||
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => ''];
|
$response = ['error' => '', 'rows' => [], 'columns' => [], 'template_id' => 0, 'filename' => '', 'apply_routine' => false];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['excel_file'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['excel_file'])) {
|
||||||
@@ -29,7 +29,7 @@ try {
|
|||||||
if ($fileError === UPLOAD_ERR_OK) {
|
if ($fileError === UPLOAD_ERR_OK) {
|
||||||
// Recupera l'ID dell'utente loggato
|
// Recupera l'ID dell'utente loggato
|
||||||
if (!isset($iduserlogin)) {
|
if (!isset($iduserlogin)) {
|
||||||
$iduserlogin = 1; // Valore di default
|
$iduserlogin = 1;
|
||||||
error_log("Warning: iduserlogin non definito, usando 1 come default");
|
error_log("Warning: iduserlogin non definito, usando 1 come default");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ try {
|
|||||||
$worksheet = $spreadsheet->getActiveSheet();
|
$worksheet = $spreadsheet->getActiveSheet();
|
||||||
$highestRow = $worksheet->getHighestRow();
|
$highestRow = $worksheet->getHighestRow();
|
||||||
$highestColumn = $worksheet->getHighestColumn();
|
$highestColumn = $worksheet->getHighestColumn();
|
||||||
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn); // Corretto
|
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn);
|
||||||
|
|
||||||
$startRow = max(1, $header_row);
|
$startRow = max(1, $header_row);
|
||||||
$startColumn = max(1, $start_column);
|
$startColumn = max(1, $start_column);
|
||||||
@@ -93,7 +93,7 @@ try {
|
|||||||
$headerRowData[] = htmlspecialchars($cellValue ?: '');
|
$headerRowData[] = htmlspecialchars($cellValue ?: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estrai i dati a partire dalla riga successiva
|
// Estrai i dati a partire dalla riga successiva, includendo excelrow
|
||||||
for ($row = $startRow + 1; $row <= $highestRow; $row++) {
|
for ($row = $startRow + 1; $row <= $highestRow; $row++) {
|
||||||
$rowData = [];
|
$rowData = [];
|
||||||
for ($col = $startColumn; $col <= $highestColumnIndex; $col++) {
|
for ($col = $startColumn; $col <= $highestColumnIndex; $col++) {
|
||||||
@@ -103,18 +103,49 @@ try {
|
|||||||
$rowData[] = htmlspecialchars($cellValue ?: '');
|
$rowData[] = htmlspecialchars($cellValue ?: '');
|
||||||
}
|
}
|
||||||
if (!empty(array_filter($rowData))) {
|
if (!empty(array_filter($rowData))) {
|
||||||
$excelData[] = $rowData;
|
$excelData[] = ['data' => $rowData, 'excelrow' => $row];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recupera routine dal template
|
||||||
|
$stmt = $pdo->prepare("SELECT idroutine, idclient FROM excel_templates WHERE id = ?");
|
||||||
|
$stmt->execute([$template_id]);
|
||||||
|
$template = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($template && $template['idroutine']) {
|
||||||
|
$stmtRoutine = $pdo->prepare("SELECT idroutine, name, filename, headerrow, instruction FROM routine WHERE idroutine = ?");
|
||||||
|
$stmtRoutine->execute([$template['idroutine']]);
|
||||||
|
$routineData = $stmtRoutine->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($routineData) {
|
||||||
|
$response['apply_routine'] = true;
|
||||||
|
$response['routine_data'] = [
|
||||||
|
'name' => $routineData['name'] ?? 'Routine Sconosciuta',
|
||||||
|
'instruction' => $routineData['instruction'] ?? 'Nessuna descrizione disponibile',
|
||||||
|
'filename' => $routineData['filename'] ?? '',
|
||||||
|
'headerrow' => $routineData['headerrow'] ?? $header_row
|
||||||
|
];
|
||||||
|
error_log("Routine rilevata per template {$template_id}: " . print_r($routineData, true));
|
||||||
|
} else {
|
||||||
|
error_log("Errore: Nessuna routine trovata per idroutine {$template['idroutine']}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log("Nessuna routine associata al template {$template_id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggiungi idclient alla risposta
|
||||||
|
$response['idclient'] = $template['idclient'] ?? null;
|
||||||
|
|
||||||
// Salva i dati in sessione
|
// Salva i dati in sessione
|
||||||
$_SESSION['excel_data'] = $excelData;
|
$_SESSION['excel_data'] = $excelData;
|
||||||
$_SESSION['template_id'] = $template_id;
|
$_SESSION['template_id'] = $template_id;
|
||||||
$_SESSION['headers'] = $headerRowData;
|
$_SESSION['headers'] = $headerRowData;
|
||||||
$_SESSION['mappings'] = $mappings; // Salva i mapping per l'importazione
|
$_SESSION['mappings'] = $mappings;
|
||||||
|
|
||||||
$response['rows'] = $excelData;
|
// Includi excel_data nella risposta JSON in ogni caso
|
||||||
$response['columns'] = $headerRowData; // Usa gli header reali
|
$response['excel_data'] = $excelData;
|
||||||
|
$response['rows'] = array_column($excelData, 'data');
|
||||||
|
$response['columns'] = $headerRowData;
|
||||||
$response['template_id'] = $template_id;
|
$response['template_id'] = $template_id;
|
||||||
$response['filename'] = $newFilename;
|
$response['filename'] = $newFilename;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,71 +15,53 @@ try {
|
|||||||
$start_column = trim($_POST['start_column']);
|
$start_column = trim($_POST['start_column']);
|
||||||
$description = trim($_POST['description'] ?? '');
|
$description = trim($_POST['description'] ?? '');
|
||||||
$target_table = trim($_POST['target_table']);
|
$target_table = trim($_POST['target_table']);
|
||||||
|
$idclient = intval($_POST['client_id'] ?? 0);
|
||||||
|
$clientname = trim($_POST['client_name'] ?? '');
|
||||||
|
$idschema = intval($_POST['idschema'] ?? 0);
|
||||||
|
$schemaname = trim($_POST['schemaname'] ?? '');
|
||||||
|
$idroutine = isset($_POST['idroutine']) && $_POST['idroutine'] !== '' ? intval($_POST['idroutine']) : null;
|
||||||
$button_size = trim($_POST['button_size'] ?? 'medium');
|
$button_size = trim($_POST['button_size'] ?? 'medium');
|
||||||
$button_bg_color = trim($_POST['button_bg_color'] ?? '#007bff');
|
$button_bg_color = trim($_POST['button_bg_color'] ?? '#007bff');
|
||||||
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
$button_text_color = trim($_POST['button_text_color'] ?? '#ffffff');
|
||||||
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
$button_label = trim($_POST['button_label'] ?? 'Click Me');
|
||||||
$idclient = intval($_POST['client_id'] ?? 0); // Usa client_id dal form
|
|
||||||
$clientname = trim($_POST['client_name'] ?? ''); // Usa client_name dal form
|
|
||||||
$status = 'active'; // Default
|
|
||||||
|
|
||||||
// Recupera i client_specific_fields (JSON inviato dal form)
|
|
||||||
$client_specific_fields = trim($_POST['client_specific_fields'] ?? '{}');
|
|
||||||
// Decodifica il JSON per verificare che sia valido (opzionale, per sicurezza)
|
|
||||||
$decoded_fields = json_decode($client_specific_fields, true);
|
|
||||||
if (json_last_error() !== JSON_ERROR_NONE && !empty($client_specific_fields)) {
|
|
||||||
throw new Exception("Invalid JSON format for client-specific fields.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recupera idschema e schemaname
|
|
||||||
$idschema = intval($_POST['idschema'] ?? 0); // Nuovo campo
|
|
||||||
$schemamaname = trim($_POST['schemamaname'] ?? ''); // Nuovo campo
|
|
||||||
|
|
||||||
// Controllo sui campi obbligatori
|
// Controllo sui campi obbligatori
|
||||||
if (empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idschema <= 0) {
|
if (empty($name) || empty($header_row) || empty($start_column) || empty($target_table) || $idclient <= 0 || $idschema <= 0) {
|
||||||
throw new Exception("All fields marked with * are required, including schema.");
|
throw new Exception("All fields marked with * are required, including client and schema.");
|
||||||
}
|
|
||||||
|
|
||||||
// Validazione del idclient
|
|
||||||
if ($idclient <= 0) {
|
|
||||||
throw new Exception("Please select a valid client.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connessione al database
|
// Connessione al database
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Inserisci nel database, aggiungendo idschema e schemaname
|
// Inserisci il nuovo template
|
||||||
$stmt = $pdo->prepare("INSERT INTO excel_templates
|
$stmt = $pdo->prepare("
|
||||||
(name, header_row, start_column, description, target_table, button_size, button_bg_color, button_text_color, button_label, idclient, clientname, status, client_specific_fields, schemaname, idschema, created_at, updated_at)
|
INSERT INTO excel_templates
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())");
|
(name, header_row, start_column, description, target_table, idclient, clientname, idschema, schemaname, idroutine,
|
||||||
|
button_size, button_bg_color, button_text_color, button_label, created_at, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||||
|
");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$name,
|
$name,
|
||||||
$header_row,
|
$header_row,
|
||||||
$start_column,
|
$start_column,
|
||||||
$description,
|
$description,
|
||||||
$target_table,
|
$target_table,
|
||||||
|
$idclient,
|
||||||
|
$clientname,
|
||||||
|
$idschema,
|
||||||
|
$schemaname,
|
||||||
|
$idroutine,
|
||||||
$button_size,
|
$button_size,
|
||||||
$button_bg_color,
|
$button_bg_color,
|
||||||
$button_text_color,
|
$button_text_color,
|
||||||
$button_label,
|
$button_label
|
||||||
$idclient,
|
|
||||||
$clientname,
|
|
||||||
$status,
|
|
||||||
$client_specific_fields,
|
|
||||||
$schemamaname,
|
|
||||||
$idschema
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($stmt->rowCount() > 0) {
|
$response["success"] = true;
|
||||||
$response["success"] = true;
|
$response["message"] = "Template created successfully!";
|
||||||
$response["message"] = "Template created successfully!";
|
|
||||||
} else {
|
|
||||||
throw new Exception("Failed to insert template.");
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$response["message"] = $e->getMessage();
|
$response["message"] = $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restituisce un JSON per il fetch
|
|
||||||
echo json_encode($response);
|
echo json_encode($response);
|
||||||
|
|||||||
@@ -0,0 +1,574 @@
|
|||||||
|
<?php
|
||||||
|
// Abilita errori per debug
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/quotations_debug.log');
|
||||||
|
if (!file_exists(__DIR__ . '/quotations_debug.log')) {
|
||||||
|
file_put_contents(__DIR__ . '/quotations_debug.log', "Inizio operazioni alle " . date('Y-m-d H:i:s') . "\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log iniziale
|
||||||
|
error_log("Inizio operazioni alle " . date('Y-m-d H:i:s'));
|
||||||
|
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// Recupera l'ID dell'utente loggato
|
||||||
|
$user_id = $iduserlogin ?? 1;
|
||||||
|
|
||||||
|
// Gestione creazione nuova quotation (crea record vuoto su conferma)
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'create') {
|
||||||
|
$description = '';
|
||||||
|
$customer = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO quotations (description, customer, iduser) VALUES (?, ?, ?)");
|
||||||
|
$success = $stmt->execute([$description, $customer, $user_id]);
|
||||||
|
if ($success) {
|
||||||
|
$newId = $pdo->lastInsertId();
|
||||||
|
error_log("Creata nuova quotation ID: $newId");
|
||||||
|
header("Location: quotations.php?edit_id=" . $newId . "&status=success&message=" . urlencode("Quotation creata con successo"));
|
||||||
|
} else {
|
||||||
|
error_log("Errore: Impossibile creare la quotation, nessun ID generato.");
|
||||||
|
header("Location: quotations.php?status=error&message=" . urlencode("Errore durante la creazione della quotation"));
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Errore PDO durante la creazione della quotation: " . $e->getMessage());
|
||||||
|
header("Location: quotations.php?status=error&message=" . urlencode("Errore database: " . $e->getMessage()));
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestione modifica quotation
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update' && isset($_POST['id'])) {
|
||||||
|
$id = intval($_POST['id']);
|
||||||
|
$description = $_POST['description'] ?? '';
|
||||||
|
$customer = $_POST['customer'] ?? '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("UPDATE quotations SET description = ?, customer = ? WHERE id = ? AND iduser = ?");
|
||||||
|
$stmt->execute([$description, $customer, $id, $user_id]);
|
||||||
|
error_log("Modificata quotation ID: $id");
|
||||||
|
header("Location: quotations.php?status=success&message=" . urlencode("Quotation modificata con successo"));
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Errore PDO durante la modifica della quotation: " . $e->getMessage());
|
||||||
|
header("Location: quotations.php?status=error&message=" . urlencode("Errore database: " . $e->getMessage()));
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestione cancellazione quotation
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete' && isset($_POST['id'])) {
|
||||||
|
$id = intval($_POST['id']);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM quotations WHERE id = ? AND iduser = ?");
|
||||||
|
$stmt->execute([$id, $user_id]);
|
||||||
|
error_log("Cancellata quotation ID: $id");
|
||||||
|
header("Location: quotations.php?status=success&message=" . urlencode("Quotation cancellata con successo"));
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Errore PDO durante la cancellazione della quotation: " . $e->getMessage());
|
||||||
|
header("Location: quotations.php?status=error&message=" . urlencode("Errore database: " . $e->getMessage()));
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recupera tutte le quotations per l'utente
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM quotations WHERE iduser = ? ORDER BY creation_date DESC");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$quotations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Errore PDO durante il recupero delle quotations: " . $e->getMessage());
|
||||||
|
$quotations = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica se è richiesta la modifica di una quotation
|
||||||
|
$editQuotation = null;
|
||||||
|
if (isset($_GET['edit_id'])) {
|
||||||
|
$editId = intval($_GET['edit_id']);
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM quotations WHERE id = ? AND iduser = ?");
|
||||||
|
$stmt->execute([$editId, $user_id]);
|
||||||
|
$editQuotation = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$editQuotation) {
|
||||||
|
error_log("Nessuna quotation trovata per id: $editId");
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Errore PDO durante il recupero della quotation per modifica: " . $e->getMessage());
|
||||||
|
$editQuotation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
||||||
|
<?php include('cssinclude.php'); ?>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2Lw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.cell-changed {
|
||||||
|
background-color: #fff3b0 !important;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.manual-input,
|
||||||
|
select.manual-input {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.required-input,
|
||||||
|
select.required-input {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
padding: 6px 8px;
|
||||||
|
margin-right: 5px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 35px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
background-color: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
background-color: #dc3545;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photos-btn {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parts-btn {
|
||||||
|
background-color: #ffc107;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group textarea {
|
||||||
|
height: 100px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flash-success {
|
||||||
|
background-color: #d4edda !important;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quotation-actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1050;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: #fefefe;
|
||||||
|
margin: 15% auto;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #888;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 600px;
|
||||||
|
border-radius: 8px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
color: #aaa;
|
||||||
|
float: right;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn:hover,
|
||||||
|
.close-btn:focus {
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.fade {
|
||||||
|
z-index: 1060 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
z-index: 1055 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay.toggle-icon {
|
||||||
|
z-index: 1000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background-color: #d4edda;
|
||||||
|
color: #155724;
|
||||||
|
border: 1px solid #c3e6cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-danger {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
color: #721c24;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>Gestione Quotations - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<?php include('include/navbar.php'); ?>
|
||||||
|
<?php include('include/topbar.php'); ?>
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<div class="page-content">
|
||||||
|
<div class="card radius-10">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div>
|
||||||
|
<h6 class="mb-0">Gestione Quotations</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<?php if (isset($_GET['status']) && isset($_GET['message'])): ?>
|
||||||
|
<div class="alert alert-<?= $_GET['status'] === 'success' ? 'success' : 'danger' ?>">
|
||||||
|
<?= htmlspecialchars(urldecode($_GET['message'])) ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($editQuotation): ?>
|
||||||
|
<!-- Modifica Quotation -->
|
||||||
|
<h6 class="mb-3">Modifica Quotation ID: <?= $editQuotation['id'] ?></h6>
|
||||||
|
<form id="editForm" method="post">
|
||||||
|
<input type="hidden" name="action" value="update">
|
||||||
|
<input type="hidden" name="id" value="<?= $editQuotation['id'] ?>">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description">Descrizione</label>
|
||||||
|
<textarea id="description" name="description" class="manual-input required-input" required><?= htmlspecialchars($editQuotation['description']) ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="customer">Cliente</label>
|
||||||
|
<input type="text" id="customer" name="customer" class="manual-input required-input" value="<?= htmlspecialchars($editQuotation['customer']) ?>" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Salva Modifiche</button>
|
||||||
|
<a href="quotations.php" class="btn btn-secondary">Torna alla Lista</a>
|
||||||
|
</form>
|
||||||
|
<div class="quotation-actions">
|
||||||
|
<h6 class="mb-3">Azioni</h6>
|
||||||
|
<button type="button" class="photos-btn action-btn" data-row="0" data-idquotations="<?= $editQuotation['id'] ?>" 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-iddatadb="" data-idquotations="<?= $editQuotation['id'] ?>" data-row="0">Parti</button>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<!-- Lista Quotations -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createModal">Crea Nuova Quotation</button>
|
||||||
|
</div>
|
||||||
|
<h6 class="mb-3">Quotations Esistenti</h6>
|
||||||
|
<table id="quotationsTable" class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Data Creazione</th>
|
||||||
|
<th>Descrizione</th>
|
||||||
|
<th>Cliente</th>
|
||||||
|
<th>Azioni</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($quotations as $index => $row): ?>
|
||||||
|
<tr data-id="<?= $row['id'] ?>">
|
||||||
|
<td><?= htmlspecialchars($row['id']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($row['creation_date']) ?></td>
|
||||||
|
<td>
|
||||||
|
<textarea name="description" class="cell-input manual-input form-control"><?= htmlspecialchars($row['description']) ?></textarea>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="customer" class="cell-input manual-input form-control" value="<?= htmlspecialchars($row['customer']) ?>">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="save-btn action-btn edit-btn" data-id="<?= $row['id'] ?>" title="Salva Modifiche"><i class="fas fa-save"></i></button>
|
||||||
|
<button type="button" class="delete-btn action-btn" data-id="<?= $row['id'] ?>" title="Cancella" data-bs-toggle="modal" data-bs-target="#deleteModal"><i class="fas fa-trash"></i></button>
|
||||||
|
<button type="button" class="photos-btn action-btn" data-entity-type="quotation" data-idquotations="<?= $row['id'] ?>" data-row="<?= $index ?>" title="Photos"><i class="fas fa-camera"></i></button>
|
||||||
|
<button type="button" class="parts-btn action-btn" data-entity-type="quotation" data-idquotations="<?= $row['id'] ?>" data-row="<?= $index ?>" title="Parts"><i class="fas fa-puzzle-piece"></i></button>
|
||||||
|
<a href="quotations.php?edit_id=<?= $row['id'] ?>" class="btn btn-secondary action-btn" title="Modifica Dettagliata"><i class="fas fa-edit"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Modal per conferma creazione nuova quotation -->
|
||||||
|
<div class="modal fade" id="createModal" tabindex="-1" aria-labelledby="createModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="createModalLabel">Conferma Creazione Nuova Quotation</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Vuoi creare una nuova quotation?</p>
|
||||||
|
<form id="createModalForm" method="post">
|
||||||
|
<input type="hidden" name="action" value="create">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="confirmCreate">Conferma</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Modal per conferma cancellazione -->
|
||||||
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="deleteModalLabel">Conferma Cancellazione</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Sicuro di voler cancellare questa quotation?</p>
|
||||||
|
<form id="deleteForm" method="post">
|
||||||
|
<input type="hidden" name="action" value="delete">
|
||||||
|
<input type="hidden" name="id" id="deleteQuotationId">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="confirmDelete">Conferma</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overlay toggle-icon"></div>
|
||||||
|
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||||
|
<?php include('include/footer.php'); ?>
|
||||||
|
</div>
|
||||||
|
<div id="partsModalContainer"></div>
|
||||||
|
<div id="annotationsModalContainer"></div>
|
||||||
|
<?php include 'photos_functions.php'; ?>
|
||||||
|
|
||||||
|
<?php include('jsinclude.php'); ?>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="photos.js"></script>
|
||||||
|
<script src="annotationsModal.js"></script>
|
||||||
|
<script src="partsTable.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
// Mostra messaggi di stato se presenti
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const status = urlParams.get('status');
|
||||||
|
const message = urlParams.get('message');
|
||||||
|
if (status && message) {
|
||||||
|
const alertDiv = document.createElement('div');
|
||||||
|
alertDiv.className = `alert alert-${status === 'success' ? 'success' : 'danger'} temp-alert`;
|
||||||
|
alertDiv.textContent = decodeURIComponent(message);
|
||||||
|
document.querySelector('.card-body').prepend(alertDiv);
|
||||||
|
setTimeout(() => {
|
||||||
|
alertDiv.remove();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on('click', '.parts-btn', function() {
|
||||||
|
const idquotations = $(this).data('idquotations');
|
||||||
|
$.ajax({
|
||||||
|
url: 'modal_partsTable.php',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
idquotations: idquotations
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
$('#partsModalContainer').html(response);
|
||||||
|
const modalElement = document.getElementById('partsModal');
|
||||||
|
if (!modalElement) return;
|
||||||
|
$("#trfHeader").text(`Quotation #${idquotations}`);
|
||||||
|
$("#partsModal").data("idquotations", idquotations);
|
||||||
|
let modal = bootstrap.Modal.getInstance(modalElement) || new bootstrap.Modal(modalElement, {
|
||||||
|
backdrop: true
|
||||||
|
});
|
||||||
|
modal.show();
|
||||||
|
if (typeof window.loadParts === 'function') window.loadParts(null, idquotations);
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
alert('Errore nel caricamento del modale: ' + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('hidden.bs.modal', '#partsModal', function() {
|
||||||
|
$('#partsModalContainer').empty();
|
||||||
|
$('.modal-backdrop').remove();
|
||||||
|
$('body').removeClass('modal-open').css('padding-right', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('hidden.bs.modal', '#annotationsModal', function() {
|
||||||
|
$('#annotationsModalContainer').empty();
|
||||||
|
$('.modal-backdrop').remove();
|
||||||
|
$('body').removeClass('modal-open').css('padding-right', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Inizializza DataTables se non siamo in modalità modifica
|
||||||
|
if (!document.querySelector('#editForm')) {
|
||||||
|
$('#quotationsTable').DataTable({
|
||||||
|
paging: true,
|
||||||
|
searching: true,
|
||||||
|
ordering: true,
|
||||||
|
info: true,
|
||||||
|
autoWidth: false,
|
||||||
|
responsive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quando il modale di creazione si apre, nascondi l'overlay
|
||||||
|
$('#createModal').on('show.bs.modal', function() {
|
||||||
|
$('.overlay.toggle-icon').css('display', 'none');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Quando il modale si chiude, ripristina l'overlay
|
||||||
|
$('#createModal').on('hide.bs.modal', function() {
|
||||||
|
$('.overlay.toggle-icon').css('display', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gestione conferma creazione nel modal
|
||||||
|
document.getElementById('confirmCreate').addEventListener('click', function() {
|
||||||
|
const createModal = bootstrap.Modal.getInstance(document.getElementById('createModal'));
|
||||||
|
createModal.hide();
|
||||||
|
const form = document.getElementById('createModalForm');
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
fetch('quotations.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}).then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Errore HTTP: ' + response.status);
|
||||||
|
}
|
||||||
|
return response.text();
|
||||||
|
}).then(() => {
|
||||||
|
window.location.href = 'quotations.php?status=success&message=' + encodeURIComponent('Quotation creata con successo');
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Errore durante la creazione della quotation:', error);
|
||||||
|
const alertDiv = document.createElement('div');
|
||||||
|
alertDiv.className = 'alert alert-danger temp-alert';
|
||||||
|
alertDiv.textContent = 'Errore durante la creazione della quotation: ' + error.message;
|
||||||
|
document.querySelector('.card-body').prepend(alertDiv);
|
||||||
|
setTimeout(() => {
|
||||||
|
alertDiv.remove();
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gestione modifica inline e save nella lista
|
||||||
|
document.querySelectorAll('.edit-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const row = this.closest('tr');
|
||||||
|
const id = row.dataset.id;
|
||||||
|
const description = row.querySelector('textarea[name="description"]').value;
|
||||||
|
const customer = row.querySelector('input[name="customer"]').value;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('action', 'update');
|
||||||
|
formData.append('id', id);
|
||||||
|
formData.append('description', description);
|
||||||
|
formData.append('customer', customer);
|
||||||
|
|
||||||
|
fetch('quotations.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
row.classList.add('flash-success');
|
||||||
|
setTimeout(() => row.classList.remove('flash-success'), 500);
|
||||||
|
alert('Quotation modificata con successo!');
|
||||||
|
} else {
|
||||||
|
alert('Errore durante la modifica.');
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Errore durante la modifica della quotation:', error);
|
||||||
|
alert('Errore durante la modifica: ' + error.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gestione apertura modal di cancellazione
|
||||||
|
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const id = this.dataset.id;
|
||||||
|
document.getElementById('deleteQuotationId').value = id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gestione conferma cancellazione nel modal
|
||||||
|
document.getElementById('confirmDelete').addEventListener('click', function() {
|
||||||
|
document.getElementById('deleteForm').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
// I bottoni photos e parts usano gli script esistenti (photos.js, parts.js), passando data-idquotations
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Modale per le foto in quotations.php -->
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$iddatadb = $data['iddatadb'] ?? null;
|
||||||
|
$parts = $data['parts'] ?? [];
|
||||||
|
|
||||||
|
if (!$iddatadb || empty($parts)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// Elimina tutte le parti esistenti per l'iddatadb per evitare conflitti di unicità
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM identification_parts WHERE iddatadb = :iddatadb");
|
||||||
|
$stmt->execute([':iddatadb' => $iddatadb]);
|
||||||
|
|
||||||
|
// Prepara l'inserimento delle nuove parti
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
INSERT INTO identification_parts
|
||||||
|
(iddatadb, part_number, part_description, mix, created_at, updated_at)
|
||||||
|
VALUES (:iddatadb, :part_number, :part_description, :mix, NOW(), NOW())
|
||||||
|
");
|
||||||
|
|
||||||
|
$part_ids = [];
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
$partNumber = $part['part_number'] ?? null;
|
||||||
|
$partDescription = $part['part_description'] ?? '';
|
||||||
|
$mix = $part['mix'] ?? 'N';
|
||||||
|
|
||||||
|
if (!$partNumber || !$partDescription) {
|
||||||
|
throw new PDOException("Numero parte o descrizione mancante per parte: " . json_encode($part));
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt->execute([
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix
|
||||||
|
]);
|
||||||
|
$part_ids[] = $pdo->lastInsertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'part_ids' => $part_ids,
|
||||||
|
'message' => 'Parti rinumerate con successo'
|
||||||
|
]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Errore nel salvataggio: ' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?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);
|
||||||
|
|
||||||
|
$idquotations = $data['idquotations'] ?? null;
|
||||||
|
$parts = $data['parts'] ?? [];
|
||||||
|
|
||||||
|
if (!$idquotations || empty($parts)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// Elimina tutte le parti esistenti per idquotations
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM identification_parts WHERE idquotations = :idquotations");
|
||||||
|
$stmt->execute([':idquotations' => $idquotations]);
|
||||||
|
|
||||||
|
// Prepara l'inserimento delle nuove parti
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
INSERT INTO identification_parts
|
||||||
|
(idquotations, part_number, part_description, mix, created_at, updated_at)
|
||||||
|
VALUES (:idquotations, :part_number, :part_description, :mix, NOW(), NOW())
|
||||||
|
");
|
||||||
|
|
||||||
|
$part_ids = [];
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
$partNumber = $part['part_number'] ?? null;
|
||||||
|
$partDescription = $part['part_description'] ?? '';
|
||||||
|
$mix = $part['mix'] ?? 'N';
|
||||||
|
|
||||||
|
if (!$partNumber || !$partDescription) {
|
||||||
|
throw new PDOException("Numero parte o descrizione mancante per parte: " . json_encode($part));
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt->execute([
|
||||||
|
':idquotations' => $idquotations,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix
|
||||||
|
]);
|
||||||
|
$part_ids[] = $pdo->lastInsertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'part_ids' => $part_ids,
|
||||||
|
'message' => 'Parti rinumerate con successo'
|
||||||
|
]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Errore nel salvataggio: ' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
ini_set('error_log', __DIR__ . '/routine_debug.log');
|
||||||
|
|
||||||
|
function applyRoutine(&$excelData, $routineData)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Log iniziale
|
||||||
|
error_log("Inizio esecuzione routine Moncler: " . date('Y-m-d H:i:s'));
|
||||||
|
error_log("Dati routine: " . print_r($routineData, true));
|
||||||
|
error_log("Dati excel_data: " . print_r($excelData, true));
|
||||||
|
|
||||||
|
// Verifica se excelData è vuoto
|
||||||
|
if (empty($excelData)) {
|
||||||
|
throw new Exception("excelData è vuoto o non valido.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estrai informazioni dalla routine con valori predefiniti
|
||||||
|
$action1 = trim($routineData['action1'] ?? 'K');
|
||||||
|
$action2 = trim($routineData['action2'] ?? 'STYLE CODE + STYLE DESCRIPTION');
|
||||||
|
$action3 = trim($routineData['action3'] ?? 'STYLE CODE');
|
||||||
|
$action4 = trim($routineData['action4'] ?? 'STYLE DESCRIPTION');
|
||||||
|
$headers = $routineData['xls_headers'] ?? [];
|
||||||
|
|
||||||
|
if (empty($headers)) {
|
||||||
|
throw new Exception("Nessun header trovato per la routine Moncler.");
|
||||||
|
}
|
||||||
|
error_log("Header ricevuti: " . print_r($headers, true));
|
||||||
|
|
||||||
|
// Normalizza gli header (solo trim)
|
||||||
|
$normalized_headers = array_map('trim', $headers);
|
||||||
|
error_log("Header normalizzati: " . print_r($normalized_headers, true));
|
||||||
|
error_log("Action values - action1: '$action1', action2: '$action2', action3: '$action3', action4: '$action4'");
|
||||||
|
|
||||||
|
// Trova gli indici delle colonne
|
||||||
|
$action1_index = array_search($action1, $normalized_headers);
|
||||||
|
$action2_index = array_search($action2, $normalized_headers);
|
||||||
|
$action3_index = array_search($action3, $normalized_headers);
|
||||||
|
$action4_index = array_search($action4, $normalized_headers);
|
||||||
|
|
||||||
|
if ($action1_index === false || $action2_index === false || $action3_index === false || $action4_index === false) {
|
||||||
|
throw new Exception("Colonne non trovate - action1: '$action1' (index: " . var_export($action1_index, true) . "), action2: '$action2' (index: " . var_export($action2_index, true) . "), action3: '$action3' (index: " . var_export($action3_index, true) . "), action4: '$action4' (index: " . var_export($action4_index, true) . ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Indici colonne - action1: $action1_index, action2: $action2_index, action3: $action3_index, action4: $action4_index");
|
||||||
|
|
||||||
|
// Raggruppa le righe per il valore in action1 (colonna K)
|
||||||
|
$grouped_data = [];
|
||||||
|
foreach ($excelData as $row) {
|
||||||
|
if (!isset($row['data']) || !is_array($row['data'])) {
|
||||||
|
error_log("Riga non valida, manca 'data' per excelrow {$row['excelrow']}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$key = $row['data'][$action1_index] ?? '';
|
||||||
|
$key = empty($key) ? '_empty_' : $key;
|
||||||
|
if (!isset($grouped_data[$key])) {
|
||||||
|
$grouped_data[$key] = [
|
||||||
|
'data' => $row['data'],
|
||||||
|
'excelrow' => [$row['excelrow']],
|
||||||
|
'style_codes' => [],
|
||||||
|
'style_descriptions' => []
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$grouped_data[$key]['excelrow'][] = $row['excelrow'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separa il valore in action2 (STYLE CODE + STYLE DESCRIPTION)
|
||||||
|
$action2_value = $row['data'][$action2_index] ?? '';
|
||||||
|
if (!empty($action2_value)) {
|
||||||
|
$parts = explode(' - ', trim($action2_value));
|
||||||
|
$style_code = $parts[0] ?? '';
|
||||||
|
$style_description = $parts[1] ?? '';
|
||||||
|
if (!empty($style_code)) {
|
||||||
|
$grouped_data[$key]['style_codes'][] = $style_code;
|
||||||
|
}
|
||||||
|
if (!empty($style_description)) {
|
||||||
|
$grouped_data[$key]['style_descriptions'][] = $style_description;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_log("Valore vuoto in action2 per excelrow {$row['excelrow']}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crea il nuovo array excel_data aggregato
|
||||||
|
$new_excel_data = [];
|
||||||
|
foreach ($grouped_data as $key => $group) {
|
||||||
|
$row_data = $group['data'];
|
||||||
|
// Aggiorna action3 (STYLE CODE) e action4 (STYLE DESCRIPTION) con valori aggregati
|
||||||
|
$row_data[$action3_index] = implode(' - ', array_unique($group['style_codes']));
|
||||||
|
$row_data[$action4_index] = implode(' - ', array_unique($group['style_descriptions']));
|
||||||
|
// Concatena gli excelrow con '+' per le righe aggregate
|
||||||
|
$excelrow_value = count($group['excelrow']) > 1 ? implode('+', $group['excelrow']) : $group['excelrow'][0];
|
||||||
|
$new_excel_data[] = [
|
||||||
|
'data' => $row_data,
|
||||||
|
'excelrow' => $excelrow_value
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifica excelData in-place
|
||||||
|
$excelData = $new_excel_data;
|
||||||
|
|
||||||
|
error_log("Routine Moncler completata - Righe aggregate: " . count($new_excel_data));
|
||||||
|
error_log("Excelrow aggregati: " . print_r(array_column($new_excel_data, 'excelrow'), true));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Eccezione nella routine Moncler: " . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +1,60 @@
|
|||||||
<?php
|
<?php
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
include('include/headscript.php'); // აქედან უნდა იყოს DB კავშირიც
|
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
|
|
||||||
$dataURL = $_POST['dataURL'] ?? null;
|
$file = $_FILES['file'] ?? null;
|
||||||
$filename = $_POST['filename'] ?? null;
|
$filename = $_POST['filename'] ?? null;
|
||||||
$iddatadb = $_POST['iddatadb'] ?? null; // 🟢 ახალი ველი
|
$iddatadb = $_POST['iddatadb'] ?? null;
|
||||||
|
|
||||||
if (!$dataURL || !$filename || !$iddatadb) {
|
if (!$file || !$filename || !$iddatadb) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_-]+\.(png|jpg|jpeg)$/', $filename)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Nome file non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_numeric($iddatadb)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedTypes = ['image/png', 'image/jpeg'];
|
||||||
|
if (!in_array($file['type'], $allowedTypes)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Formato file non supportato']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// --- ფაილის შენახვა ---
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
$data = explode(',', $dataURL)[1];
|
$pdo = $dbHandler->getConnection();
|
||||||
$decodedData = base64_decode($data);
|
$stmt = $pdo->prepare("SELECT iddatadb FROM datadb WHERE iddatadb = :iddatadb");
|
||||||
|
$stmt->execute([':iddatadb' => $iddatadb]);
|
||||||
|
if (!$stmt->fetch()) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'iddatadb non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$dirPath = '../photostrf/annotated';
|
$dirPath = '../photostrf/annotated';
|
||||||
if (!file_exists($dirPath)) {
|
if (!file_exists($dirPath)) {
|
||||||
mkdir($dirPath, 0777, true);
|
mkdir($dirPath, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$filePath = $dirPath . '/' . $filename;
|
$filePath = $dirPath . '/' . $filename;
|
||||||
file_put_contents($filePath, $decodedData);
|
if (file_exists($filePath)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'File già esistente']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$db = DBHandlerSelect::getInstance();
|
if (!move_uploaded_file($file['tmp_name'], $filePath)) {
|
||||||
$pdo = $db->getConnection();
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio del file']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// --- ბაზაში ჩაწერა ---
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
INSERT INTO datadb_photos (iddatadb, file_path, file_name, uploaded_at, uploaded_by)
|
INSERT INTO datadb_photos (iddatadb, file_path, file_name, uploaded_at, uploaded_by)
|
||||||
VALUES (:iddatadb, :file_path, :file_name, NOW(), :uploaded_by)
|
VALUES (:iddatadb, :file_path, :file_name, NOW(), :uploaded_by)
|
||||||
@@ -39,7 +63,7 @@ try {
|
|||||||
':iddatadb' => $iddatadb,
|
':iddatadb' => $iddatadb,
|
||||||
':file_path' => $filePath,
|
':file_path' => $filePath,
|
||||||
':file_name' => $filename,
|
':file_name' => $filename,
|
||||||
':uploaded_by'=> $iduserlogin
|
':uploaded_by' => $iduserlogin
|
||||||
]);
|
]);
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
@@ -47,7 +71,6 @@ try {
|
|||||||
'file_path' => $filePath,
|
'file_path' => $filePath,
|
||||||
'message' => 'Foto salvata con successo e registrata nel DB'
|
'message' => 'Foto salvata con successo e registrata nel DB'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore: ' . $e->getMessage()]);
|
echo json_encode(['success' => false, 'message' => 'Errore: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
|
||||||
|
$file = $_FILES['file'] ?? null;
|
||||||
|
$filename = $_POST['filename'] ?? null;
|
||||||
|
$idquotations = $_POST['idquotations'] ?? null;
|
||||||
|
|
||||||
|
if (!$file || !$filename || !$idquotations || !isset($iduserlogin)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti o utente non autenticato']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_-]+\.(png|jpg|jpeg)$/', $filename)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Nome file non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_numeric($idquotations)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedTypes = ['image/png', 'image/jpeg'];
|
||||||
|
if (!in_array($file['type'], $allowedTypes)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Formato file non supportato']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM quotations WHERE id = :idquotations");
|
||||||
|
$stmt->execute([':idquotations' => $idquotations]);
|
||||||
|
if (!$stmt->fetch()) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'idquotations non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dirPath = '../photostrf/annotated';
|
||||||
|
if (!file_exists($dirPath)) {
|
||||||
|
mkdir($dirPath, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$filePath = $dirPath . '/' . $filename;
|
||||||
|
if (file_exists($filePath)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'File già esistente']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!move_uploaded_file($file['tmp_name'], $filePath)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio del file']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
INSERT INTO datadb_photos (idquotations, file_path, file_name, uploaded_at, uploaded_by)
|
||||||
|
VALUES (:idquotations, :file_path, :file_name, NOW(), :uploaded_by)
|
||||||
|
");
|
||||||
|
$stmt->execute([
|
||||||
|
':idquotations' => $idquotations,
|
||||||
|
':file_path' => $filePath,
|
||||||
|
':file_name' => $filename,
|
||||||
|
':uploaded_by' => $iduserlogin
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'file_path' => $filePath,
|
||||||
|
'message' => 'Foto salvata con successo e registrata nel DB'
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -11,13 +11,78 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$iddatadb = intval($_POST['iddatadb']);
|
$iddatadb = intval($_POST['iddatadb']);
|
||||||
$db = DBHandlerSelect::getInstance();
|
$idclient = isset($_POST['idclient']) ? (is_numeric($_POST['idclient']) ? intval($_POST['idclient']) : null) : null;
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
// ---------------- FIXED FIELDS (template_fixed_mapping) ----------------
|
||||||
|
|
||||||
|
// ALIAS: fixed_field_key "logico" -> colonna reale su datadb
|
||||||
|
// (NON tocchiamo MySQL, gestiamo solo qui la traduzione)
|
||||||
|
$fixedAliasMap = [
|
||||||
|
'ClienteResponsabile' => 'cliente_responsabile_id',
|
||||||
|
'MoltiplicatorePrezzo' => 'moltiplicatore_prezzo_id',
|
||||||
|
'AnagraficaCertestObject' => 'anagrafica_certest_object_id',
|
||||||
|
'AnagraficaCertestService' => 'anagrafica_certest_service_id',
|
||||||
|
'ClienteFornitore' => 'cliente_fornitore_id',
|
||||||
|
'ConsegnaRichiesta' => 'consegna_richiesta',
|
||||||
|
];
|
||||||
|
|
||||||
|
// 1) Recupera templateid dalla riga datadb (serve per sapere quali fixed_field_key sono permessi)
|
||||||
|
$stmtTpl = $pdo->prepare("SELECT templateid FROM datadb WHERE iddatadb = ?");
|
||||||
|
$stmtTpl->execute([$iddatadb]);
|
||||||
|
$tplRow = $stmtTpl->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$templateId = isset($tplRow['templateid']) ? (int)$tplRow['templateid'] : 0;
|
||||||
|
if ($templateId <= 0) {
|
||||||
|
throw new Exception("Template non trovato per iddatadb=$iddatadb");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Recupera elenco fixed fields visibili per quel template
|
||||||
|
$fxStmt = $pdo->prepare("
|
||||||
|
SELECT fixed_field_key, data_type, is_required, default_value
|
||||||
|
FROM template_fixed_mapping
|
||||||
|
WHERE template_id = ? AND is_visible_import = 1
|
||||||
|
");
|
||||||
|
$fxStmt->execute([$templateId]);
|
||||||
|
$fixedList = $fxStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// 3) Crea whitelist LOGICA: fixed_field_key => metadata
|
||||||
|
$fixedWhitelist = [];
|
||||||
|
foreach ($fixedList as $fx) {
|
||||||
|
$k = (string)$fx['fixed_field_key'];
|
||||||
|
|
||||||
|
// sicurezza: key ammessa solo se "safe"
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_]+$/', $k)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fixedWhitelist[$k] = [
|
||||||
|
'data_type' => (string)$fx['data_type'], // INT | DATE
|
||||||
|
'is_required' => (int)$fx['is_required'],
|
||||||
|
'default_value' => $fx['default_value'] ?? null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3b) Crea whitelist REALE: colonna datadb reale => metadata
|
||||||
|
$realWhitelist = [];
|
||||||
|
foreach ($fixedWhitelist as $logicalKey => $meta) {
|
||||||
|
$realCol = $fixedAliasMap[$logicalKey] ?? $logicalKey;
|
||||||
|
|
||||||
|
// sicurezza: anche la colonna reale deve essere "safe"
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_]+$/', $realCol)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$realWhitelist[$realCol] = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- DETAILS (import_data_details) ----------------
|
||||||
$data = $_POST;
|
$data = $_POST;
|
||||||
$details = [];
|
$details = [];
|
||||||
|
|
||||||
// 1. POST-დან ამოვიღოთ მხოლოდ details
|
// 1. Estrarre i dettagli da POST
|
||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
if (preg_match('/^details(\d+)field_value$/', $key, $matches)) {
|
if (preg_match('/^details(\d+)field_value$/', $key, $matches)) {
|
||||||
$id = $matches[1];
|
$id = $matches[1];
|
||||||
@@ -25,16 +90,15 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. DB-დან წამოვიღოთ არსებული მნიშვნელობები
|
// 2. Recupera i valori esistenti da import_data_details
|
||||||
$stmt = $pdo->prepare("SELECT mapping_id, field_value FROM import_data_details WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT mapping_id, field_value FROM import_data_details WHERE id = ?");
|
||||||
$stmt->execute([$iddatadb]);
|
$stmt->execute([$iddatadb]);
|
||||||
|
|
||||||
$currentValues = [];
|
$currentValues = [];
|
||||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
$currentValues[$row['mapping_id']] = $row['field_value'];
|
$currentValues[$row['mapping_id']] = $row['field_value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. შევადაროთ POST-ს და DB-ს
|
// 3. Confronta i valori nuovi con quelli esistenti
|
||||||
$changed = [];
|
$changed = [];
|
||||||
foreach ($details as $id => $newValue) {
|
foreach ($details as $id => $newValue) {
|
||||||
$oldValue = $currentValues[$id] ?? null;
|
$oldValue = $currentValues[$id] ?? null;
|
||||||
@@ -46,7 +110,7 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. თუ არის ცვლილებები → UPDATE
|
// 4. Aggiorna i dettagli se ci sono modifiche
|
||||||
if (!empty($changed)) {
|
if (!empty($changed)) {
|
||||||
$updateStmt = $pdo->prepare("
|
$updateStmt = $pdo->prepare("
|
||||||
UPDATE import_data_details
|
UPDATE import_data_details
|
||||||
@@ -56,20 +120,87 @@ try {
|
|||||||
|
|
||||||
foreach ($changed as $mappingId => $values) {
|
foreach ($changed as $mappingId => $values) {
|
||||||
$updateStmt->execute([
|
$updateStmt->execute([
|
||||||
':newValue' => $values['new'],
|
':newValue' => $values['new'],
|
||||||
':iddatadb' => $iddatadb,
|
':iddatadb' => $iddatadb,
|
||||||
':mappingId' => $mappingId
|
':mappingId' => $mappingId
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$response['success'] = true;
|
// ---------------- UPDATE datadb: idclient + FIXED FIELDS ----------------
|
||||||
$response['message'] = "Updated successfully";
|
$setParts = [];
|
||||||
$response['changed'] = $changed; // Debug / optional
|
$params = [];
|
||||||
|
|
||||||
|
// 5a) idclient (se presente)
|
||||||
|
if (isset($idclient)) {
|
||||||
|
$setParts[] = "idclient = ?";
|
||||||
|
$params[] = $idclient;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5b) fixed fields dal POST
|
||||||
|
// QUI è il punto chiave: accettiamo SOLO colonne reali (realWhitelist),
|
||||||
|
// ma se dal JS arrivassero ancora key logiche, funzionerebbe uguale
|
||||||
|
// perché sotto controlliamo anche l'alias.
|
||||||
|
foreach ($realWhitelist as $realCol => $meta) {
|
||||||
|
|
||||||
|
$postKeyToRead = null;
|
||||||
|
|
||||||
|
// Caso 1: POST contiene già la colonna reale
|
||||||
|
if (array_key_exists($realCol, $_POST)) {
|
||||||
|
$postKeyToRead = $realCol;
|
||||||
|
} else {
|
||||||
|
// Caso 2: POST contiene la key logica -> troviamo quale logica mappa su questa colonna reale
|
||||||
|
// (fallback, utile se non hai ancora aggiornato il JS)
|
||||||
|
foreach ($fixedAliasMap as $logical => $mappedReal) {
|
||||||
|
if ($mappedReal === $realCol && array_key_exists($logical, $_POST)) {
|
||||||
|
$postKeyToRead = $logical;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($postKeyToRead === null) {
|
||||||
|
continue; // non inviato
|
||||||
|
}
|
||||||
|
|
||||||
|
$val = $_POST[$postKeyToRead];
|
||||||
|
|
||||||
|
// Normalizzazione per tipo
|
||||||
|
if ($meta['data_type'] === 'DATE') {
|
||||||
|
$val = trim((string)$val);
|
||||||
|
$val = ($val === '') ? null : $val; // atteso formato Y-m-d
|
||||||
|
} else { // INT
|
||||||
|
$val = trim((string)$val);
|
||||||
|
$val = ($val === '') ? null : (int)$val;
|
||||||
|
}
|
||||||
|
|
||||||
|
$setParts[] = "`$realCol` = ?";
|
||||||
|
$params[] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// esegui update solo se c'è qualcosa da aggiornare
|
||||||
|
if (!empty($setParts)) {
|
||||||
|
$params[] = $iddatadb;
|
||||||
|
|
||||||
|
$sqlUpd = "UPDATE datadb SET " . implode(", ", $setParts) . " WHERE iddatadb = ?";
|
||||||
|
$updStmt = $pdo->prepare($sqlUpd);
|
||||||
|
$updStmt->execute($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messaggio risposta (mantengo la tua logica ma includo fixed)
|
||||||
|
if (!empty($setParts) && !empty($changed)) {
|
||||||
|
$response['message'] = "Updated details and datadb fields successfully";
|
||||||
|
} elseif (!empty($setParts)) {
|
||||||
|
$response['message'] = "Updated datadb fields successfully";
|
||||||
|
} elseif (!empty($changed)) {
|
||||||
|
$response['message'] = "Updated details successfully";
|
||||||
} else {
|
} else {
|
||||||
$response['success'] = true;
|
|
||||||
$response['message'] = "No changes found";
|
$response['message'] = "No changes found";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$response['success'] = true;
|
||||||
|
$response['changed'] = $changed; // Debug / optional
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$response['success'] = false;
|
$response['success'] = false;
|
||||||
$response['message'] = $e->getMessage();
|
$response['message'] = $e->getMessage();
|
||||||
|
|||||||
@@ -20,19 +20,82 @@ $mappingId = $data['id'];
|
|||||||
$mappingType = $data['mapping_type'] ?? '';
|
$mappingType = $data['mapping_type'] ?? '';
|
||||||
$excelColumn = $data['excel_column'] ?? null;
|
$excelColumn = $data['excel_column'] ?? null;
|
||||||
$manualDefault = $data['manual_default'] ?? null;
|
$manualDefault = $data['manual_default'] ?? null;
|
||||||
|
|
||||||
|
$autoValue = $data['auto_value'] ?? 'none';
|
||||||
$tablename = $data['tablename'] ?? '';
|
$tablename = $data['tablename'] ?? '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("UPDATE template_mapping SET is_manual = ?, excel_column = ?, manual_default = ? WHERE id = ?");
|
// Normalize mapping type
|
||||||
$isManual = ($mappingType === 'manual') ? 1 : 0;
|
$allowedTypes = ['', 'xls', 'manual', 'auto'];
|
||||||
$result = $stmt->execute([$isManual, $excelColumn, $manualDefault, $mappingId]);
|
if (!in_array($mappingType, $allowedTypes, true)) {
|
||||||
|
echo json_encode(["success" => false, "message" => "Invalid mapping_type"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize auto_value
|
||||||
|
$allowedAuto = ['none', 'import_date', 'import_time', 'export_date', 'export_time'];
|
||||||
|
if (!in_array($autoValue, $allowedAuto, true)) {
|
||||||
|
$autoValue = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide what to persist based on mapping_type
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
|
||||||
|
if ($mappingType === 'xls') {
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = $excelColumn ?: null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
} elseif ($mappingType === 'manual') {
|
||||||
|
$isManual = 1;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = $manualDefault;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
} elseif ($mappingType === 'auto') {
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = $autoValue ?: 'none';
|
||||||
|
} else {
|
||||||
|
// reset
|
||||||
|
$isManual = 0;
|
||||||
|
$excelToSave = null;
|
||||||
|
$manualToSave = null;
|
||||||
|
$autoToSave = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
UPDATE template_mapping
|
||||||
|
SET
|
||||||
|
is_manual = ?,
|
||||||
|
excel_column = ?,
|
||||||
|
manual_default = ?,
|
||||||
|
auto_value = ?
|
||||||
|
WHERE id = ?
|
||||||
|
");
|
||||||
|
|
||||||
|
$result = $stmt->execute([$isManual, $excelToSave, $manualToSave, $autoToSave, $mappingId]);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
echo json_encode(["success" => false, "message" => "Database update failed"]);
|
echo json_encode(["success" => false, "message" => "Database update failed"]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode(["success" => true, "message" => "Mapping updated successfully", "data" => $data]); // Aggiunto debug
|
echo json_encode([
|
||||||
|
"success" => true,
|
||||||
|
"message" => "Mapping updated successfully",
|
||||||
|
"saved" => [
|
||||||
|
"id" => (int)$mappingId,
|
||||||
|
"mapping_type" => $mappingType,
|
||||||
|
"is_manual" => $isManual,
|
||||||
|
"excel_column" => $excelToSave,
|
||||||
|
"manual_default" => $manualToSave,
|
||||||
|
"auto_value" => $autoToSave
|
||||||
|
]
|
||||||
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
|
echo json_encode(["success" => false, "message" => "Error: " . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$iddatadb = $data['iddatadb'] ?? null;
|
||||||
|
$parts = $data['parts'] ?? [];
|
||||||
|
|
||||||
|
if (!$iddatadb || empty($parts)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$part = $parts[0];
|
||||||
|
$partId = $part['id'] ?? null;
|
||||||
|
$idmatrice = $part['idmatrice'] ?? null;
|
||||||
|
|
||||||
|
if (!$partId) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID parte mancante']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("UPDATE identification_parts
|
||||||
|
SET idmatrice = :idmatrice,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = :id");
|
||||||
|
$stmt->execute([
|
||||||
|
':id' => $partId,
|
||||||
|
':idmatrice' => $idmatrice // Può essere NULL
|
||||||
|
]);
|
||||||
|
echo json_encode(['success' => true, 'message' => 'Matrice aggiornata con successo']);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio della matrice: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -15,46 +15,64 @@ if (!$iddatadb || empty($parts)) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$part = $parts[0];
|
try {
|
||||||
$partId = $part['id'] ?? null; // part_id თუ არსებობს
|
$pdo->beginTransaction();
|
||||||
$partNumber = $part['part_number'] ?? null;
|
$results = [];
|
||||||
$partDescription = $part['part_description'] ?? '';
|
|
||||||
$mix = $part['mix'] ?? 'N';
|
|
||||||
|
|
||||||
if ($partDescription) {
|
foreach ($parts as $part) {
|
||||||
try {
|
$partId = $part['id'] ?? null;
|
||||||
if ($partId) {
|
$partNumber = $part['part_number'] ?? null;
|
||||||
// UPDATE თუ უკვე არსებობს part
|
$partDescription = $part['part_description'] ?? '';
|
||||||
$stmt = $pdo->prepare("UPDATE identification_parts
|
$mix = $part['mix'] ?? 'N';
|
||||||
SET part_number = :part_number,
|
$idmatrice = $part['idmatrice'] ?? null;
|
||||||
part_description = :part_description,
|
$note = $part['note'] ?? null;
|
||||||
mix = :mix,
|
$dateexpiry = $part['dateexpiry'] ?? null;
|
||||||
updated_at = NOW()
|
|
||||||
WHERE id = :id");
|
if ($partDescription || $note || $dateexpiry) {
|
||||||
$stmt->execute([
|
if ($partId) {
|
||||||
':id' => $partId,
|
// UPDATE se la parte esiste
|
||||||
':part_number' => $partNumber,
|
$stmt = $pdo->prepare("UPDATE identification_parts
|
||||||
':part_description' => $partDescription,
|
SET part_number = :part_number,
|
||||||
':mix' => $mix
|
part_description = :part_description,
|
||||||
]);
|
mix = :mix,
|
||||||
echo json_encode(['success' => true, 'part_id' => $partId, 'part_number'=>$partNumber, 'message' => 'Parte aggiornata con successo']);
|
idmatrice = :idmatrice,
|
||||||
} else {
|
note = :note,
|
||||||
// INSERT თუ ახალია
|
dateexpiry = :dateexpiry,
|
||||||
$stmt = $pdo->prepare("INSERT INTO identification_parts
|
updated_at = NOW()
|
||||||
(iddatadb, part_number, part_description, mix, created_at, updated_at)
|
WHERE id = :id");
|
||||||
VALUES (:iddatadb, :part_number, :part_description, :mix, NOW(), NOW())");
|
$stmt->execute([
|
||||||
$stmt->execute([
|
':id' => $partId,
|
||||||
':iddatadb' => $iddatadb,
|
':part_number' => $partNumber,
|
||||||
':part_number' => $partNumber,
|
':part_description' => $partDescription,
|
||||||
':part_description' => $partDescription,
|
':mix' => $mix,
|
||||||
':mix' => $mix
|
':idmatrice' => $idmatrice,
|
||||||
]);
|
':note' => $note,
|
||||||
$newId = $pdo->lastInsertId();
|
':dateexpiry' => $dateexpiry,
|
||||||
echo json_encode(['success' => true, 'part_id' => $newId, 'part_number'=>$partNumber, 'message' => 'Parte salvata con successo']);
|
]);
|
||||||
|
$results[] = ['part_id' => $partId, 'part_number' => $partNumber, 'message' => 'Parte aggiornata con successo'];
|
||||||
|
} else {
|
||||||
|
// INSERT per nuova parte
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO identification_parts
|
||||||
|
(iddatadb, part_number, part_description, mix, idmatrice, note, dateexpiry, created_at, updated_at)
|
||||||
|
VALUES (:iddatadb, :part_number, :part_description, :mix, :idmatrice, :note, :dateexpiry, NOW(), NOW())");
|
||||||
|
$stmt->execute([
|
||||||
|
':iddatadb' => $iddatadb,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix,
|
||||||
|
':idmatrice' => $idmatrice,
|
||||||
|
':note' => $note,
|
||||||
|
':dateexpiry' => $dateexpiry,
|
||||||
|
]);
|
||||||
|
$newId = $pdo->lastInsertId();
|
||||||
|
$results[] = ['part_id' => $newId, 'part_number' => $partNumber, 'message' => 'Parte salvata con successo'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Descrizione mancante']);
|
$pdo->commit();
|
||||||
|
echo json_encode(['success' => true, 'results' => $results]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
$dbHandler = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $dbHandler->getConnection();
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$iddatadb = $data['iddatadb'] ?? null;
|
||||||
|
$partIds = $data['partIds'] ?? [];
|
||||||
|
$photoList = $data['photoList'] ?? null;
|
||||||
|
|
||||||
|
if ($iddatadb) {
|
||||||
|
if (count($partIds) != 0) {
|
||||||
|
$idList = array_values(array_map('intval', $partIds));
|
||||||
|
$placeholders = [];
|
||||||
|
$parameters = [':iddatadb' => $iddatadb];
|
||||||
|
|
||||||
|
foreach ($idList as $index => $id) {
|
||||||
|
$paramName = ":id{$index}";
|
||||||
|
$placeholders[] = $paramName;
|
||||||
|
$parameters[$paramName] = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'UPDATE identification_parts SET iddatadb = :iddatadb WHERE id IN (' . implode(',', $placeholders) . ')';
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($photoList) != 0) {
|
||||||
|
$placeholders = [];
|
||||||
|
$parameters = [':iddatadb' => $iddatadb];
|
||||||
|
|
||||||
|
foreach ($photoList as $index => $photo) {
|
||||||
|
$paramName = ":photo{$index}";
|
||||||
|
$placeholders[] = $paramName;
|
||||||
|
$parameters[$paramName] = $photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('UPDATE datadb_photos SET iddatadb = :iddatadb WHERE file_path IN (' . implode(',', $placeholders) . ')');
|
||||||
|
$stmt->execute($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'message' => '']);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?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);
|
||||||
|
|
||||||
|
$idquotations = $data['idquotations'] ?? null;
|
||||||
|
$parts = $data['parts'] ?? [];
|
||||||
|
|
||||||
|
if (!$idquotations || empty($parts)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$part = $parts[0];
|
||||||
|
$partId = $part['id'] ?? null;
|
||||||
|
$partNumber = $part['part_number'] ?? null;
|
||||||
|
$partDescription = $part['part_description'] ?? '';
|
||||||
|
$mix = $part['mix'] ?? 'N';
|
||||||
|
|
||||||
|
if ($partDescription) {
|
||||||
|
try {
|
||||||
|
if ($partId) {
|
||||||
|
// UPDATE se esiste già la parte
|
||||||
|
$stmt = $pdo->prepare("UPDATE identification_parts
|
||||||
|
SET part_number = :part_number,
|
||||||
|
part_description = :part_description,
|
||||||
|
mix = :mix,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = :id");
|
||||||
|
$stmt->execute([
|
||||||
|
':id' => $partId,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix
|
||||||
|
]);
|
||||||
|
echo json_encode(['success' => true, 'part_id' => $partId, 'part_number' => $partNumber, 'message' => 'Parte aggiornata con successo']);
|
||||||
|
} else {
|
||||||
|
// INSERT se è nuova
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO identification_parts
|
||||||
|
(idquotations, part_number, part_description, mix, created_at, updated_at)
|
||||||
|
VALUES (:idquotations, :part_number, :part_description, :mix, NOW(), NOW())");
|
||||||
|
$stmt->execute([
|
||||||
|
':idquotations' => $idquotations,
|
||||||
|
':part_number' => $partNumber,
|
||||||
|
':part_description' => $partDescription,
|
||||||
|
':mix' => $mix
|
||||||
|
]);
|
||||||
|
$newId = $pdo->lastInsertId();
|
||||||
|
echo json_encode(['success' => true, 'part_id' => $newId, 'part_number' => $partNumber, 'message' => 'Parte salvata con successo']);
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Descrizione mancante']);
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,60 +1,881 @@
|
|||||||
{
|
{
|
||||||
"@odata.context": "https:\/\/93.43.5.102\/limsapi\/api\/odata\/$metadata#SchemaCustomField",
|
"@odata.context": "https:\/\/bvcpsitaly-elims.com\/limsapi\/api\/odata\/$metadata#SchemaCustomField",
|
||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 41,
|
"IdSchemaCustomFields": 41,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Labostudio",
|
"Nome": "Labostudio",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 42,
|
"IdSchemaCustomFields": 42,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Schema 1",
|
"Nome": "Schema 1",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 43,
|
"IdSchemaCustomFields": 43,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Schema1",
|
"Nome": "Schema1",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 44,
|
"IdSchemaCustomFields": 44,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Cuoio\/Pelle Standard \/ Leather",
|
"Nome": "Cuoio\/Pelle Standard \/ Leather",
|
||||||
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 45,
|
"IdSchemaCustomFields": 45,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Borse",
|
"Nome": "Borse",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 46,
|
"IdSchemaCustomFields": 46,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Borse Burberry",
|
"Nome": "Borse Burberry",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 47,
|
"IdSchemaCustomFields": 47,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "pelle calzatura",
|
"Nome": "pelle calzatura",
|
||||||
"Descrizione": null
|
"Descrizione": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 48,
|
"IdSchemaCustomFields": 48,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Standard Generico \/ Generic Standard",
|
"Nome": "Standard Generico \/ Generic Standard",
|
||||||
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 49,
|
"IdSchemaCustomFields": 49,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Accessori Metallici \/ Metallic Accessories",
|
"Nome": "Accessori Metallici \/ Metallic Accessories",
|
||||||
"Descrizione": "Schema per tutti gli Accessori Metallici\r\n\r\n\r\n"
|
"Descrizione": "Schema per tutti gli Accessori Metallici\r\n\r\n\r\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 50,
|
"IdSchemaCustomFields": 50,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "Tessile \/ Textiles",
|
"Nome": "Tessile \/ Textiles",
|
||||||
"Descrizione": "Schema per tutti i Tessuti\r\n"
|
"Descrizione": "Schema per tutti i Tessuti\r\n"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 52,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Brasport",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 54,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel Calzatura",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 55,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Burberry",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 57,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Ralph Lauren - Tessile",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in tessuto per Ralph Lauren.\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 58,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LIU JO",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 59,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Migrazione tra Componenti",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 60,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Prova Outsourcing",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 61,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Marc Jacobs",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 62,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "A. TESTONI",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 63,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel CHINA PROJECT",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 66,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GUESS",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 68,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Valentino",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 69,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DESIGUAL",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 70,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FENDI PELLETTERIA",
|
||||||
|
"Descrizione": "Solo per FENDI Pelletteria_INGLESE\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 71,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Cuoio\/Pelle Standard ACCREDIA",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 72,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_BALLY",
|
||||||
|
"Descrizione": "sia per calzatura che pelletteria. Aggiunto campo TEST DESCRIPTION, compreso nella fatturazione per le divisioni pelletteria.\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 73,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Ralph Lauren - Leather",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 74,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Ralph Lauren - Fabric",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 76,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "NORDSTROM",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 77,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ONWARD LUXURY GROUP",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 78,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "P&G SRL_Progetto Durability",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 79,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Bally qualsiasi divisione",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 80,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FENDI CALZATURA",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 81,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LouBoutin",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"IdSchemaCustomFields": 82,
|
"IdSchemaCustomFields": 82,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
"Nome": "MONCLER Brand",
|
"Nome": "MONCLER Brand",
|
||||||
"Descrizione": "Da utilizzare solo per il Brand Diretto\r\nGR 19\/03\/2024"
|
"Descrizione": "Da utilizzare solo per il Brand Diretto\r\nGR 19\/03\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 83,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "JIMMY CHOO",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 84,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Yves Saint Laurent",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 85,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BENETTON",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 86,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "UPLOAD REPORT",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 87,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes Calzatura",
|
||||||
|
"Descrizione": "\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 88,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "C&A",
|
||||||
|
"Descrizione": "Schema per fornitori e C&A diretto\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 89,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AMERICAN EAGLE",
|
||||||
|
"Descrizione": "Schema per American Eagle\/Todd snyder\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 91,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Ferragamo",
|
||||||
|
"Descrizione": "\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 93,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Alexander McQueen",
|
||||||
|
"Descrizione": "\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 95,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Balenciaga Pelletteria",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 96,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DUNHILL",
|
||||||
|
"Descrizione": "SCHEMA DUNHILL tutti i tipi di campioni\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 97,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PRELIEVI ACQUE",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 98,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LouBoutin_Tossicologico",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 99,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ROBAN'S ",
|
||||||
|
"Descrizione": "tutte le divisioni\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 100,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PROGETTO LUGGAGE",
|
||||||
|
"Descrizione": "Progetto Luggage Hermes\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 102,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Balmain",
|
||||||
|
"Descrizione": "Schema per tutti i campioni Balmain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 103,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ZDHC",
|
||||||
|
"Descrizione": "Schema di Riferimento ZDHC Wastewaters"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 104,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GUCCI CDC 4172",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 105,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ASOS",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 106,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_BOUX AVENUE",
|
||||||
|
"Descrizione": "28\/09 no indicazioni su esigenze di fatturazione (detto da Frosini)\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 107,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BONPOINT",
|
||||||
|
"Descrizione": "05\/10 creazione\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 108,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Canada Goose",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 109,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DIESEL",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 110,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AQC_Leather",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 111,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BEAUMANOIR (CC-Mor-Bon-Breal)",
|
||||||
|
"Descrizione": "04\/02\/21_ AGGIORNATO 05\/08\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 112,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BooHoo",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 114,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Golden Goose",
|
||||||
|
"Descrizione": "Golden goose\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 115,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ZLABEL",
|
||||||
|
"Descrizione": "Schema per ZLABEL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 116,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Zadig & Voltaire",
|
||||||
|
"Descrizione": "Schema per Zadig & Voltaire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 117,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Gemo",
|
||||||
|
"Descrizione": "Schema solo per Gemo\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 118,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PROMOD",
|
||||||
|
"Descrizione": "CHF 06\/08\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 119,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LA HALLE (BEAUMANOIR)",
|
||||||
|
"Descrizione": "13\/08\/2021 CHF\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 120,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LA REDOUTE",
|
||||||
|
"Descrizione": "14\/09\/2021 AD\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 121,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TOD'S",
|
||||||
|
"Descrizione": "Schema per materiale gb18401 e GB20400\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 122,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ASOS rev 1",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 123,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Monoprix",
|
||||||
|
"Descrizione": "Schema per Monoprix\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 124,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DIOR Ita",
|
||||||
|
"Descrizione": "CHF 21\/03\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 125,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GEOX - Raw Material",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER GEOX - SOLO PER LE SUOLE E MATERIALI DENOMINATI RPU \/ RAW MATERIAL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 126,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CAMAIEU",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER CAMAIEU\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 127,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Golden Goose FTW",
|
||||||
|
"Descrizione": "Golden goose\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 128,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "STEVE MADDEN - FOOTWEAR",
|
||||||
|
"Descrizione": "DA UTILIZZARE SOLO PER DESTINAZIONE D'USO CALZATURA\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 129,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_Carhartt",
|
||||||
|
"Descrizione": "SCHEMA DA UTILIZZARE SOLO PER RICHIESTE UFFICIALI CARHARTT\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 131,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DAMART",
|
||||||
|
"Descrizione": "\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 132,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Gruppo OTB",
|
||||||
|
"Descrizione": "Schema per Staff International, Diesel e Brave kid\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 133,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FERRARI",
|
||||||
|
"Descrizione": "Schema da usare per Ferrari e fornitori\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 134,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GAP - ABBIGLIAMENTO",
|
||||||
|
"Descrizione": "Schema GAP da utilizzare solo per destinazione abbigliamento\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 135,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GAP - CALZATURA",
|
||||||
|
"Descrizione": "Schema GAP da utilizzare solo per destinazione calzatura\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 136,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "SALLING GROUP",
|
||||||
|
"Descrizione": "Schema per Salling Group\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 137,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "SOFT SURROUNDINGS",
|
||||||
|
"Descrizione": "Schema da utilizzare per Soft Surroundings\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 138,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "E-LIMS - Cuoio\/Pelle Standard \/ Leather",
|
||||||
|
"Descrizione": "Schema da utilizzare solo per accettazioni online\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 139,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ZALANDO",
|
||||||
|
"Descrizione": "Schema per ZALANDO ------ (NON per ZLABEL che ha il suo)\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 140,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LVMH",
|
||||||
|
"Descrizione": "gennaio 2023\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 141,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Valentino - eLims",
|
||||||
|
"Descrizione": "SCHEMA DA UTILIZZARE SOLO PER L'ACCETTAZIONE ONLINE DI VALENTINO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 142,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "FENDI PELLETTERIA COMPLIANCE",
|
||||||
|
"Descrizione": "Solo per FENDI Pelletteria_INGLESE 04\/05\/2023\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 143,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TAPESTRY",
|
||||||
|
"Descrizione": "04\/05\/2023, agg secondo procedura 08\/11\/23\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 144,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ALEXANDER MC QUEEN",
|
||||||
|
"Descrizione": "ALEXANDER MC QUEEN 15\/05\/2023\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 145,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes_Chimici_Parigi",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 146,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CELINE ABBIGLIAMENTO_Progetto Speciale",
|
||||||
|
"Descrizione": "IO 202 CELINE ABBIGLIAMENTO_06\/06\/203_CHF\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 147,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "GEOX - Prodotto Finito",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER GEOX - SOLO PER PRODOTTO FINITO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 149,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes\/IDO",
|
||||||
|
"Descrizione": "creato il 05\/07\/2023 CHF\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 150,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Tessile \/ Textiles PER CLIENTI CON OBLO",
|
||||||
|
"Descrizione": "Schema per tutti i Tessuti QUANDO IL CLIENTE NECESSITA DI NR OBLO\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 151,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "J JIll",
|
||||||
|
"Descrizione": "Schema per cliente J JIll, necessario riportare la recommended fiber content in schema verde\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 152,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AUCHAN - TAPE A L'OEIL",
|
||||||
|
"Descrizione": "Schema AUCHAN da utilizzare solo per la divisione TAPE A L'OEIL SA, successivamente se uguale da usare anche per le altre divisioni ed uniformarlo come generico"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 153,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ALL SAINTS - BUSCEMI",
|
||||||
|
"Descrizione": "SCHE DA USARE SOLO PER ALL SAINTS E BUSCEMI\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 154,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CELINE - LVMH",
|
||||||
|
"Descrizione": "Schema con aggiunta campi LVMH per estrazioni\r\nAD-29\/03\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 155,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "SeyMeChamLou",
|
||||||
|
"Descrizione": "DA USARE SOLO PER SEYMECHAMLOU (LOUBOUTIN)\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 156,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PRADA",
|
||||||
|
"Descrizione": "PER ADESSO DA USARE PER ABBIGLIAMENTO E CALZATURA\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 157,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes_HCP",
|
||||||
|
"Descrizione": "Schema per unicamente HCP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 158,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "STONE ISLAND",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 159,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel_Pierre Damien",
|
||||||
|
"Descrizione": "Schema da usare per Campioni ricevuti da Pierre-Damien Verine e suo staff CHANEL.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 160,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Z_ACNE",
|
||||||
|
"Descrizione": "\r\n.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 161,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "OBERALP GROUP",
|
||||||
|
"Descrizione": "Schema da usare solo per Oberalp Group\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 162,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Club Monaco",
|
||||||
|
"Descrizione": "da usare solo per Club Monaco GR 20\/02\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 163,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Devred",
|
||||||
|
"Descrizione": "Schema creato per cliente DEVRED\r\nGR 18\/03\/2024\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 164,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "MONCLER Supplier",
|
||||||
|
"Descrizione": "Da utilizzare per fornitori Moncler \r\nGR 19\/03\/2024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 165,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Kering Sunglasses",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 166,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Giorgio Armani",
|
||||||
|
"Descrizione": "\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 167,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chanel USA",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 168,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Staff Calzatura",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 169,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "P&G SRL",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 170,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "INCOM",
|
||||||
|
"Descrizione": "Schema da utilizzare per INCOM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 171,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "RIVER ISLAND",
|
||||||
|
"Descrizione": "SCHEDA DA USARE SOLO PER RIVER ISLAND - NO CALZATURA\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 172,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Longchamp",
|
||||||
|
"Descrizione": "Schema per tutti i campioni con RIchiesta Longchamp ufficiale\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 173,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Bottega Veneta",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di Bottega Veneta di Stella"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 174,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Mint Velvet",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di Mint Velvel con richiesta ufficiale.\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 176,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "RIVER ISLAND FOOTWEAR",
|
||||||
|
"Descrizione": "SCHEDA DA USARE SOLO PER RIVER ISLAND - USARE SOLO PER\r\n CALZATURA\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 177,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Phoebe philo ACC",
|
||||||
|
"Descrizione": "(scarpe, borse, cinture, occhiali, gioielleria)\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 178,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "New Guards Group",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 179,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Giorgio Armani Operation",
|
||||||
|
"Descrizione": "\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 180,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chloe'",
|
||||||
|
"Descrizione": "\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 181,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LVMH non diretti",
|
||||||
|
"Descrizione": "utilizzato ogni qualvolta siano caricati pacchetti \/ prove singole che non rientrano nel programma LVMH \r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 182,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Ralph Lauren - All testing V.6",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 183,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TWINSET",
|
||||||
|
"Descrizione": "Schema da usare per Twinset - come da mail di EP del 20\/05\/2025\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 184,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ACNE STUDIOS rev 01",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 185,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Brunello cucinelli",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 186,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TWINSET",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di qualsiasi matrice escluso cuoio\/pelle\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 187,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LORO PIANA",
|
||||||
|
"Descrizione": "Schema per tutti i campioni Loro Piana\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 188,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LEMAIRE",
|
||||||
|
"Descrizione": "Schema per tutti i campioni in cuoio\/pelle per i quali non \u00e8 specificato un destinatario.\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 189,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "TEST_IT_SCHEMA",
|
||||||
|
"Descrizione": "Test per IT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 190,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "LBS Interscambio",
|
||||||
|
"Descrizione": "Schema per tutti i campioni interscambio LBS\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 191,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "KIABI",
|
||||||
|
"Descrizione": "Schema per il cliente Kiabi\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 192,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "INDITEX",
|
||||||
|
"Descrizione": "Schema da usare solo per richieste INDITEX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 193,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "AQC_Other materials",
|
||||||
|
"Descrizione": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 194,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Hermes ADM & Silk",
|
||||||
|
"Descrizione": "SCHEMA DA USARE SOLO PER LA DIVISIONE ADM & SILK\r\n\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 195,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "Chloe'_APPAREL",
|
||||||
|
"Descrizione": "Schema aggiornato il 18\/12\/25 secondo modulo excel x codifica Elims\r\nGR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 196,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "DUNHILL_DRAFT NON USARE",
|
||||||
|
"Descrizione": "SCHEMA DUNHILL NON USARE STUDIO NUOVA PROCEDURA NOVEMBRE 2025\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 197,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "BERLUTI - LVMH",
|
||||||
|
"Descrizione": "Creato per accettazione Elims\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 198,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "PIAGET (gruppo Cartier)",
|
||||||
|
"Descrizione": "Schema per tutti i campioni PIAGET (gruppo Cartier)\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 199,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "HERMES PAP FEMME",
|
||||||
|
"Descrizione": "Schema per tutti i campioni di HERMES PAP FEMME \r\n15\/01\/2025\r\n\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 200,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "CARHARTT ( provvisiorio in revisione)",
|
||||||
|
"Descrizione": "Schema per tutti i campioni CARHARTT provvissorio\r\n\r\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"IdSchemaCustomFields": 201,
|
||||||
|
"ConteggioClienti": 0,
|
||||||
|
"Nome": "ROSSIMODA",
|
||||||
|
"Descrizione": "Per tutti i campioni di ROSSIMODA\r\n\r\n"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
require_once "class/VisualLimsApiClient.class.php";
|
||||||
|
include('include/headscript.php');
|
||||||
|
|
||||||
|
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 commessaId
|
||||||
|
$commessaId = 533357;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 🔹 Initialize API client
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// 🔹 STEP 1: POST InviaCommessa
|
||||||
|
$logContentStep1 = "curl --location --request POST '{$apiBaseUrl}CommessaWeb({$commessaId})/InviaCommessa' \\\n" .
|
||||||
|
"--header 'Content-Type: application/json' \\\n" .
|
||||||
|
"--header 'Authorization: Bearer ••••••' \\\n" .
|
||||||
|
"--data '{}'\n\n";
|
||||||
|
|
||||||
|
$sendResult = $api->post("CommessaWeb({$commessaId})/InviaCommessa", []);
|
||||||
|
|
||||||
|
$logContentStep1 .= "RESPONSE:\n" . json_encode($sendResult, JSON_PRETTY_PRINT);
|
||||||
|
$logFileStep1 = $logDir . "commessa_{$commessaId}_send_step1_" . time() . ".txt";
|
||||||
|
file_put_contents($logFileStep1, $logContentStep1);
|
||||||
|
|
||||||
|
// 🔹 STEP 2: GET di controllo post-invio
|
||||||
|
$expand = "CommesseCustomFields(\$expand=CustomField)";
|
||||||
|
$commessaAfterSend = $api->get("CommessaWeb(" . $commessaId . ")?\$expand=" . $expand);
|
||||||
|
|
||||||
|
// Log curl-like per GET di controllo
|
||||||
|
$logContentStep2 = "curl --location --request GET '{$apiBaseUrl}CommessaWeb({$commessaId})?\$expand=CommesseCustomFields(\$expand=CustomField)' \\\n" .
|
||||||
|
"--header 'Authorization: Bearer ••••••'\n\n" .
|
||||||
|
"RESPONSE:\n" . json_encode($commessaAfterSend, JSON_PRETTY_PRINT);
|
||||||
|
$logFileStep2 = $logDir . "commessa_{$commessaId}_get_step2_" . time() . ".txt";
|
||||||
|
file_put_contents($logFileStep2, $logContentStep2);
|
||||||
|
|
||||||
|
// 🔹 Output a schermo
|
||||||
|
echo json_encode([
|
||||||
|
"success" => true,
|
||||||
|
"message" => "Commessa {$commessaId} inviata e verificata",
|
||||||
|
"sendResult" => $sendResult,
|
||||||
|
"commessaAfterSend" => $commessaAfterSend,
|
||||||
|
"logFiles" => [
|
||||||
|
"step1_send" => $logFileStep1,
|
||||||
|
"step2_get" => $logFileStep2
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Send/Check Error: " . $e->getMessage() . "\nTrace: " . $e->getTraceAsString());
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
"success" => false,
|
||||||
|
"message" => "Operation failed: " . $e->getMessage(),
|
||||||
|
"logFiles" => [
|
||||||
|
"step1_send" => $logFileStep1 ?? null,
|
||||||
|
"step2_get" => $logFileStep2 ?? null
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -90,11 +90,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($nametemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
<th><?= htmlspecialchars($lastmodtemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
|
||||||
<th><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($rowheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
<th><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($columnheader, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($desctemplate, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
<th>Client Name</th>
|
<th>Client Name</th>
|
||||||
|
<th>Button Label</th>
|
||||||
<th>Status</th> <!-- Aggiunta colonna Status -->
|
<th>Status</th> <!-- Aggiunta colonna Status -->
|
||||||
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
<th><?= htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?></th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -147,13 +147,7 @@
|
|||||||
data: 'name', // Nome del template
|
data: 'name', // Nome del template
|
||||||
title: "Template Name"
|
title: "Template Name"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
data: 'updated_at', // Ultima modifica, formattata come data leggibile
|
|
||||||
title: "Last Modified",
|
|
||||||
render: function(data) {
|
|
||||||
return new Date(data).toLocaleDateString();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
data: 'header_row', // Riga degli header
|
data: 'header_row', // Riga degli header
|
||||||
title: "Header Row"
|
title: "Header Row"
|
||||||
@@ -176,6 +170,11 @@
|
|||||||
return `${clientName} (ID: ${clientId})`;
|
return `${clientName} (ID: ${clientId})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
data: 'button_label', // Nuova colonna per Button Label
|
||||||
|
title: "Button Label",
|
||||||
|
defaultContent: 'Click Me'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
data: 'status', // Stato con Toggle Switch
|
data: 'status', // Stato con Toggle Switch
|
||||||
title: "Status",
|
title: "Status",
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
// File: test_auth.php
|
||||||
|
ini_set('display_errors', '0');
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
|
||||||
|
// Includi le dipendenze
|
||||||
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||||
|
require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Crea la cartella logsapi se non esiste
|
||||||
|
$logDir = __DIR__ . '/logsapi';
|
||||||
|
if (!is_dir($logDir)) {
|
||||||
|
mkdir($logDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Istanzia il client API (autenticazione automatica tramite .env)
|
||||||
|
$api = VisualLimsApiClient::getInstance();
|
||||||
|
|
||||||
|
// Esegui una chiamata di test per verificare l'autenticazione
|
||||||
|
$endpoint = 'SchemaCustomField';
|
||||||
|
$options = []; // Nessun filtro per il test
|
||||||
|
$data = $api->get($endpoint, $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($logDir . '/last_auth_url.txt', $full_url . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
// Nota: getToken() è privato, quindi non possiamo accedervi direttamente
|
||||||
|
// Supponiamo che l'autenticazione sia avvenuta correttamente se la GET ha successo
|
||||||
|
$token = null; // Non possiamo accedere al token direttamente
|
||||||
|
$auth_success = true; // La GET ha successo, quindi l'autenticazione funziona
|
||||||
|
|
||||||
|
// Salva un file di conferma dell'autenticazione
|
||||||
|
$outputFile = $logDir . '/auth_token.json';
|
||||||
|
file_put_contents($outputFile, json_encode(['auth_success' => true, 'token' => 'Not directly accessible (private method)'], JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
// Risposta di successo
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'message' => "Autenticazione completata con successo, dettagli salvati in {$outputFile}",
|
||||||
|
'auth_success' => $auth_success,
|
||||||
|
'schema_data' => $data // Dati di esempio dalla GET
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Log dell'errore
|
||||||
|
file_put_contents($logDir . '/auth_error.log', date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Errore durante l\'autenticazione: ' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
require_once(__DIR__ . '/include/headscript.php');
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$id = (int)($input['id'] ?? 0);
|
||||||
|
$field = (string)($input['field'] ?? '');
|
||||||
|
$value = $input['value'] ?? null;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid id']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed = ['default_value', 'is_visible_import', 'is_required'];
|
||||||
|
if (!in_array($field, $allowed, true)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid field']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($field === 'is_visible_import' || $field === 'is_required') {
|
||||||
|
$value = ((int)$value === 1) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$sql = "UPDATE template_fixed_mapping SET {$field} = :val WHERE id = :id";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$ok = $stmt->execute([':val' => $value, ':id' => $id]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => (bool)$ok]);
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'include/headscript.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
$template_id = $data['template_id'] ?? null;
|
||||||
|
$mapping_id = $data['mapping_id'] ?? null;
|
||||||
|
$value = $data['value'] ?? null;
|
||||||
|
|
||||||
|
if (!$template_id || !$mapping_id || !isset($value)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid input']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("UPDATE template_mapping SET is_visible_import = ? WHERE id = ? AND template_id = ?");
|
||||||
|
$result = $stmt->execute([$value, $mapping_id, $template_id]);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Failed to update is_visible_import']);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'include/headscript.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
$template_id = isset($data['template_id']) ? (int)$data['template_id'] : 0;
|
||||||
|
$mapping_id = isset($data['mapping_id']) ? (int)$data['mapping_id'] : 0;
|
||||||
|
$value = isset($data['value']) ? (int)$data['value'] : null;
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if ($template_id <= 0 || $mapping_id <= 0 || $value === null) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid input']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize to 0/1
|
||||||
|
$value = ($value === 1) ? 1 : 0;
|
||||||
|
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("UPDATE template_mapping SET is_visible_parts = ? WHERE id = ? AND template_id = ?");
|
||||||
|
$result = $stmt->execute([$value, $mapping_id, $template_id]);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Failed to update is_visible_parts']);
|
||||||
|
}
|
||||||
@@ -4,13 +4,23 @@ include('include/headscript.php');
|
|||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['photo']) || !isset($_POST['iddatadb'])) {
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['photo']) || (!isset($_POST['iddatadb']) && !isset($_POST['idquotations']))) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Richiesta non valida']);
|
echo json_encode(['success' => false, 'message' => 'Richiesta non valida']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$iddatadb = intval($_POST['iddatadb']);
|
$iddatadb = isset($_POST['iddatadb']) ? intval($_POST['iddatadb']) : null;
|
||||||
$photo = $_FILES['photo'];
|
$idquotations = isset($_POST['idquotations']) ? intval($_POST['idquotations']) : null;
|
||||||
|
|
||||||
|
if ($iddatadb && $idquotations) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Non è possibile specificare sia iddatadb che idquotations']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$iddatadb && !$idquotations) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID TRF o ID quotations mancante']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Verifica che l'utente loggato esista in auth_users
|
// Verifica che l'utente loggato esista in auth_users
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
@@ -25,6 +35,28 @@ if (!$userExists) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifica l'esistenza dell'ID nella tabella corrispondente
|
||||||
|
try {
|
||||||
|
if ($iddatadb) {
|
||||||
|
$stmt = $pdo->prepare("SELECT iddatadb FROM datadb WHERE iddatadb = ?");
|
||||||
|
$stmt->execute([$iddatadb]);
|
||||||
|
if (!$stmt->fetch()) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'iddatadb non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM quotations WHERE id = ?");
|
||||||
|
$stmt->execute([$idquotations]);
|
||||||
|
if (!$stmt->fetch()) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'idquotations non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore nella validazione: ' . $e->getMessage()]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Usa un percorso assoluto per la cartella photostrf
|
// Usa un percorso assoluto per la cartella photostrf
|
||||||
$uploadDir = realpath(__DIR__ . '/../photostrf') . '/';
|
$uploadDir = realpath(__DIR__ . '/../photostrf') . '/';
|
||||||
if (!is_dir($uploadDir)) {
|
if (!is_dir($uploadDir)) {
|
||||||
@@ -41,6 +73,7 @@ if (!is_writable($uploadDir)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verifica che il file sia un'immagine (inclusi HEIC/HEIF)
|
// Verifica che il file sia un'immagine (inclusi HEIC/HEIF)
|
||||||
|
$photo = $_FILES['photo'];
|
||||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/heic', 'image/heif'];
|
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/heic', 'image/heif'];
|
||||||
if (!in_array($photo['type'], $allowedTypes)) {
|
if (!in_array($photo['type'], $allowedTypes)) {
|
||||||
echo json_encode(['success' => false, 'message' => 'Il file deve essere un\'immagine (JPEG, PNG, GIF, HEIC)']);
|
echo json_encode(['success' => false, 'message' => 'Il file deve essere un\'immagine (JPEG, PNG, GIF, HEIC)']);
|
||||||
@@ -53,10 +86,11 @@ if (!file_exists($photo['tmp_name']) || !is_uploaded_file($photo['tmp_name'])) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rinomina il file: idriga-timestamp-nomeoriginale.estensione
|
// Rinomina il file: id-timestamp-nomeoriginale.estensione
|
||||||
$timestamp = date('YmdHis');
|
$timestamp = date('YmdHis');
|
||||||
$originalName = pathinfo($photo['name'], PATHINFO_FILENAME);
|
$originalName = pathinfo($photo['name'], PATHINFO_FILENAME);
|
||||||
$extension = strtolower(pathinfo($photo['name'], PATHINFO_EXTENSION));
|
$extension = strtolower(pathinfo($photo['name'], PATHINFO_EXTENSION));
|
||||||
|
$id = $iddatadb ?: $idquotations;
|
||||||
|
|
||||||
// Se il file è HEIC/HEIF, convertilo in JPEG
|
// Se il file è HEIC/HEIF, convertilo in JPEG
|
||||||
if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
|
if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
|
||||||
@@ -74,11 +108,11 @@ if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Crea un nuovo nome per il file JPEG
|
// Crea un nuovo nome per il file JPEG
|
||||||
$newFileName = "{$iddatadb}-{$timestamp}-{$originalName}.jpg";
|
$newFileName = "{$id}-{$timestamp}-{$originalName}.jpg";
|
||||||
$destination = $uploadDir . $newFileName;
|
$destination = $uploadDir . $newFileName;
|
||||||
|
|
||||||
// Salva l'immagine come JPEG
|
// Salva l'immagine come JPEG
|
||||||
if (!imagejpeg($image, $destination, 90)) { // 90 è la qualità JPEG
|
if (!imagejpeg($image, $destination, 90)) {
|
||||||
imagedestroy($image);
|
imagedestroy($image);
|
||||||
echo json_encode(['success' => false, 'message' => 'Errore durante la conversione del file HEIC in JPEG']);
|
echo json_encode(['success' => false, 'message' => 'Errore durante la conversione del file HEIC in JPEG']);
|
||||||
exit;
|
exit;
|
||||||
@@ -88,7 +122,7 @@ if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
|
|||||||
imagedestroy($image);
|
imagedestroy($image);
|
||||||
} else {
|
} else {
|
||||||
// Per i formati non HEIC, usa il nome e l'estensione originali
|
// Per i formati non HEIC, usa il nome e l'estensione originali
|
||||||
$newFileName = "{$iddatadb}-{$timestamp}-{$originalName}.{$extension}";
|
$newFileName = "{$id}-{$timestamp}-{$originalName}.{$extension}";
|
||||||
$destination = $uploadDir . $newFileName;
|
$destination = $uploadDir . $newFileName;
|
||||||
|
|
||||||
// Salva il file
|
// Salva il file
|
||||||
@@ -105,7 +139,12 @@ error_log("Destination: $destination");
|
|||||||
error_log("Temp file: " . $photo['tmp_name']);
|
error_log("Temp file: " . $photo['tmp_name']);
|
||||||
|
|
||||||
// Salva il riferimento nel database
|
// Salva il riferimento nel database
|
||||||
$stmt = $pdo->prepare("INSERT INTO datadb_photos (iddatadb, file_path, file_name, uploaded_by) VALUES (?, ?, ?, ?)");
|
try {
|
||||||
$stmt->execute([$iddatadb, $newFileName, $newFileName, $iduserlogin]);
|
$stmt = $pdo->prepare("INSERT INTO datadb_photos (iddatadb, idquotations, file_path, file_name, uploaded_by) VALUES (?, ?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$iddatadb, $idquotations, $newFileName, $newFileName, $iduserlogin]);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore durante il salvataggio nel database: ' . $e->getMessage()]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode(['success' => true, 'message' => 'Foto caricata con successo']);
|
echo json_encode(['success' => true, 'message' => 'Foto caricata con successo']);
|
||||||
|
|||||||
@@ -1,28 +1,45 @@
|
|||||||
<?php
|
<?php
|
||||||
// upload_photos_mobile.php
|
// upload_photos_mobile.php
|
||||||
include('include/headscript.php');
|
include('include/headscriptnologin.php');
|
||||||
|
|
||||||
$db = DBHandlerSelect::getInstance();
|
$db = DBHandlerSelect::getInstance();
|
||||||
$pdo = $db->getConnection();
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
// Verifica che l'iddatadb sia stato passato
|
// Verifica che almeno uno degli ID sia passato
|
||||||
if (!isset($_GET['iddatadb']) || empty($_GET['iddatadb'])) {
|
$iddatadb = isset($_GET['iddatadb']) && !empty($_GET['iddatadb']) ? intval($_GET['iddatadb']) : null;
|
||||||
die('ID riga non fornito');
|
$idquotations = isset($_GET['idquotations']) && !empty($_GET['idquotations']) ? intval($_GET['idquotations']) : null;
|
||||||
|
|
||||||
|
if (!$iddatadb && !$idquotations) {
|
||||||
|
die('ID riga o ID quotations non fornito');
|
||||||
}
|
}
|
||||||
|
|
||||||
$iddatadb = intval($_GET['iddatadb']);
|
if ($iddatadb && $idquotations) {
|
||||||
|
die('Non è possibile specificare sia iddatadb che idquotations');
|
||||||
|
}
|
||||||
|
|
||||||
// Recupera i dettagli della riga (idriga e sample_code)
|
// Verifica che l'utente loggato esista
|
||||||
$stmt = $pdo->prepare("SELECT iddatadb, sample_code FROM datadb WHERE iddatadb = ?");
|
$stmt = $pdo->prepare("SELECT id FROM auth_users WHERE id = ?");
|
||||||
$stmt->execute([$iddatadb]);
|
$stmt->execute([$iduserlogin]);
|
||||||
|
if (!$stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
die('Utente non valido');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determina quale ID usare e verifica l'esistenza
|
||||||
|
$paramName = $iddatadb ? 'iddatadb' : 'idquotations';
|
||||||
|
$paramValue = $iddatadb ?: $idquotations;
|
||||||
|
$table = $iddatadb ? 'datadb' : 'quotations';
|
||||||
|
$field = $iddatadb ? 'sample_code' : 'quotation_code';
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT {$paramName}, {$field} FROM {$table} WHERE {$paramName} = ?");
|
||||||
|
$stmt->execute([$paramValue]);
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (!$row) {
|
if (!$row) {
|
||||||
die('Riga non trovata');
|
die('Riga non trovata');
|
||||||
}
|
}
|
||||||
|
|
||||||
$idriga = $row['iddatadb'];
|
$id = $row[$paramName];
|
||||||
$sampleCode = $row['sample_code'] ?? 'Non disponibile';
|
$code = $row[$field] ?? 'Non disponibile';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -32,17 +49,23 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Carica Foto da Mobile</title>
|
<title>Carica Foto da Mobile</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
background: #f4f4f4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-area {
|
.upload-area {
|
||||||
border: 2px dashed #ccc;
|
border: 2px dashed #ccc;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
margin: 20px 0;
|
margin: 20px auto;
|
||||||
|
max-width: 500px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-area.highlight {
|
.upload-area.highlight {
|
||||||
@@ -56,57 +79,121 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
|
max-width: 500px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.photo-item img {
|
.photo-item img {
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
max-height: 100px;
|
max-height: 100px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader i {
|
||||||
|
font-size: 40px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
margin: 10px 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.delete-photo-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #dc3545;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h2>Carica Foto per ID Riga: <?= htmlspecialchars($idriga) ?></h2>
|
<h2>Carica Foto per ID: <?= htmlspecialchars($id) ?></h2>
|
||||||
<p><strong>Sample Code:</strong> <?= htmlspecialchars($sampleCode) ?></p>
|
<p><strong>Codice:</strong> <?= htmlspecialchars($code) ?></p>
|
||||||
|
<div class="loader" id="loader">
|
||||||
|
<div>
|
||||||
|
<i class="fas fa-spinner fa-spin"></i>
|
||||||
|
<p>Caricamento in corso...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="error-message" id="errorMessage"></div>
|
||||||
<div class="upload-area" id="uploadArea">
|
<div class="upload-area" id="uploadArea">
|
||||||
<p>Scatta una foto o seleziona un'immagine</p>
|
<p>Scatta una foto o seleziona immagini</p>
|
||||||
<input type="file" id="photoInput" accept="image/*" capture="camera">
|
<input type="file" id="photoInput" accept="image/*" capture="camera" multiple style="display: none;">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="photosList">
|
|
||||||
<!-- Le foto verranno caricate dinamicamente -->
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="photosList"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const uploadArea = document.getElementById('uploadArea');
|
const uploadArea = document.getElementById('uploadArea');
|
||||||
const photoInput = document.getElementById('photoInput');
|
const photoInput = document.getElementById('photoInput');
|
||||||
const photosList = document.getElementById('photosList');
|
const photosList = document.getElementById('photosList');
|
||||||
|
const loader = document.getElementById('loader');
|
||||||
|
const errorMessage = document.getElementById('errorMessage');
|
||||||
|
const iddatadb = '<?= $iddatadb ?>';
|
||||||
|
const idquotations = '<?= $idquotations ?>';
|
||||||
|
const endpoint = idquotations ? 'load_photo_quotation.php' : 'load_photo.php';
|
||||||
|
const dataParam = idquotations ? {
|
||||||
|
idquotations: idquotations
|
||||||
|
} : {
|
||||||
|
iddatadb: iddatadb
|
||||||
|
};
|
||||||
|
|
||||||
// Carica le foto esistenti all'avvio
|
// Carica le foto esistenti all'avvio
|
||||||
loadPhotos();
|
loadPhotos();
|
||||||
|
|
||||||
// Gestione del click sull'area di upload
|
// Gestione drag-and-drop
|
||||||
uploadArea.addEventListener('click', () => {
|
uploadArea.addEventListener('dragover', (e) => {
|
||||||
photoInput.click();
|
e.preventDefault();
|
||||||
|
uploadArea.classList.add('highlight');
|
||||||
|
});
|
||||||
|
uploadArea.addEventListener('dragleave', () => {
|
||||||
|
uploadArea.classList.remove('highlight');
|
||||||
|
});
|
||||||
|
uploadArea.addEventListener('drop', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadArea.classList.remove('highlight');
|
||||||
|
handleFiles(e.dataTransfer.files);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gestione del caricamento delle foto
|
// Gestione click sull'area di upload
|
||||||
photoInput.addEventListener('change', () => {
|
uploadArea.addEventListener('click', () => photoInput.click());
|
||||||
handleFiles(photoInput.files);
|
|
||||||
});
|
// Gestione caricamento foto
|
||||||
|
photoInput.addEventListener('change', () => handleFiles(photoInput.files));
|
||||||
|
|
||||||
async function handleFiles(files) {
|
async function handleFiles(files) {
|
||||||
|
loader.style.display = 'flex';
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (!file.type.startsWith('image/')) {
|
if (!file.type.startsWith('image/')) {
|
||||||
alert('Per favore, carica solo immagini!');
|
showError('Per favore, carica solo immagini!');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('photo', file);
|
formData.append('photo', file);
|
||||||
formData.append('iddatadb', '<?= $iddatadb ?>');
|
if (iddatadb) formData.append('iddatadb', iddatadb);
|
||||||
|
if (idquotations) formData.append('idquotations', idquotations);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('upload_photo.php', {
|
const response = await fetch('upload_photo.php', {
|
||||||
@@ -114,31 +201,85 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
|
|||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
if (!result.success) {
|
||||||
if (result.success) {
|
showError('Errore durante il caricamento: ' + result.message);
|
||||||
loadPhotos(); // Ricarica le foto
|
|
||||||
} else {
|
|
||||||
alert('Errore durante il caricamento: ' + result.message);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert('Errore durante il caricamento: ' + error.message);
|
showError('Errore di rete: ' + error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
loadPhotos();
|
||||||
|
loader.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funzione per caricare le foto esistenti
|
|
||||||
async function loadPhotos() {
|
async function loadPhotos() {
|
||||||
|
loader.style.display = 'flex';
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`photos_popup.php?iddatadb=<?= $iddatadb ?>`);
|
const response = await fetch(`${endpoint}?${new URLSearchParams(dataParam)}`);
|
||||||
const html = await response.text();
|
const result = await response.json();
|
||||||
const parser = new DOMParser();
|
photosList.innerHTML = '';
|
||||||
const doc = parser.parseFromString(html, 'text/html');
|
if (result.success && result.photos && result.photos.length > 0) {
|
||||||
const photosListContent = doc.querySelector('#photosList').innerHTML;
|
for (const photo of result.photos) {
|
||||||
photosList.innerHTML = photosListContent;
|
const photoName = photo.split('/').pop();
|
||||||
|
const photoItem = document.createElement('div');
|
||||||
|
photoItem.className = 'photo-item';
|
||||||
|
photoItem.innerHTML = `
|
||||||
|
<img src="${photo}" alt="${photoName}">
|
||||||
|
<div style="flex: 1; text-align: left;">
|
||||||
|
<strong>Nome:</strong> ${photoName}<br>
|
||||||
|
<strong>Caricata il:</strong> Non disponibile
|
||||||
|
</div>
|
||||||
|
<button class="delete-photo-btn" data-photo-path="${photo}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>`;
|
||||||
|
photosList.appendChild(photoItem);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
photosList.innerHTML = '<p>Nessuna foto presente.</p>';
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
photosList.innerHTML = `<p>Errore durante il caricamento delle foto: ${error.message}</p>`;
|
showError('Errore durante il caricamento delle foto: ' + error.message);
|
||||||
}
|
}
|
||||||
|
loader.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
errorMessage.textContent = message;
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
setTimeout(() => errorMessage.style.display = 'none', 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestione eliminazione foto
|
||||||
|
photosList.addEventListener('click', async (e) => {
|
||||||
|
if (e.target.closest('.delete-photo-btn')) {
|
||||||
|
const button = e.target.closest('.delete-photo-btn');
|
||||||
|
const photoPath = button.dataset.photoPath;
|
||||||
|
if (confirm('Sei sicuro di voler eliminare questa foto?')) {
|
||||||
|
loader.style.display = 'flex';
|
||||||
|
try {
|
||||||
|
const response = await fetch('delete_photo.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
file_path: photoPath
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
loadPhotos();
|
||||||
|
} else {
|
||||||
|
showError('Errore durante l\'eliminazione: ' + result.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError('Errore durante l\'eliminazione: ' + error.message);
|
||||||
|
}
|
||||||
|
loader.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -1,30 +1,38 @@
|
|||||||
@if ($socialProviders)
|
@if ($socialProviders)
|
||||||
<?php $colSize = 12 / count($socialProviders); ?>
|
<?php $colSize = 12 / count($socialProviders); ?>
|
||||||
|
|
||||||
<div class="row pb-3 pt-2">
|
<div class="row pb-3 pt-2">
|
||||||
@if (in_array('facebook', $socialProviders))
|
@if (in_array('facebook', $socialProviders))
|
||||||
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
||||||
<a href="{{ url('auth/facebook/login') }}" class="btn-facebook">
|
<a href="{{ url('auth/facebook/login') }}" class="btn-facebook">
|
||||||
<i class="fab fa-facebook fa-2x"></i>
|
<i class="fab fa-facebook fa-2x"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (in_array('twitter', $socialProviders))
|
|
||||||
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
|
||||||
<a href="{{ url('auth/twitter/login') }}" class="btn-twitter">
|
|
||||||
<i class="fab fa-twitter fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (in_array('google', $socialProviders))
|
|
||||||
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
|
||||||
<a href="{{ url('auth/google/login') }}" class="btn-google">
|
|
||||||
<i class="fab fa-google-plus-square fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (in_array('twitter', $socialProviders))
|
||||||
|
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
||||||
|
<a href="{{ url('auth/twitter/login') }}" class="btn-twitter">
|
||||||
|
<i class="fab fa-twitter fa-2x"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (in_array('google', $socialProviders))
|
||||||
|
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
||||||
|
<a href="{{ url('auth/google/login') }}" class="btn-google">
|
||||||
|
<i class="fab fa-google-plus-square fa-2x"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (in_array('microsoft', $socialProviders))
|
||||||
|
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
||||||
|
<a href="{{ url('auth/microsoft/login') }}" class="btn-microsoft">
|
||||||
|
<i class="fab fa-microsoft fa-2x"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authentication
|
* Authentication
|
||||||
*/
|
*/
|
||||||
@@ -196,3 +198,25 @@ Route::get('/userarea/upload-photos-mobile', [UploadPhotosMobileController::clas
|
|||||||
|
|
||||||
Route::post('/userarea/upload-photos-mobile', [UploadPhotosMobileController::class, 'upload'])
|
Route::post('/userarea/upload-photos-mobile', [UploadPhotosMobileController::class, 'upload'])
|
||||||
->name('userarea.upload-photos-mobile.upload');
|
->name('userarea.upload-photos-mobile.upload');
|
||||||
|
|
||||||
|
// Microsoft Auth Routes
|
||||||
|
Route::get('/auth/microsoft/login', function () {
|
||||||
|
return Socialite::driver('microsoft')->redirect();
|
||||||
|
})->name('auth.microsoft');
|
||||||
|
|
||||||
|
Route::get('/auth/microsoft/callback', function () {
|
||||||
|
try {
|
||||||
|
$user = Socialite::driver('microsoft')->user();
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'SUCCESS',
|
||||||
|
'user_data' => [
|
||||||
|
'id' => $user->getId(),
|
||||||
|
'name' => $user->getName(),
|
||||||
|
'email' => $user->getEmail(),
|
||||||
|
'avatar' => $user->getAvatar(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return response()->json(['status' => 'ERROR', 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
})->name('auth.microsoft.callback');
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user