diff --git a/py_app/DATABASE_SETUP_README.md b/DATABASE_SETUP_README.md similarity index 100% rename from py_app/DATABASE_SETUP_README.md rename to DATABASE_SETUP_README.md diff --git a/logs/access.log b/logs/access.log new file mode 100644 index 0000000..0ea576c --- /dev/null +++ b/logs/access.log @@ -0,0 +1,59 @@ +127.0.0.1 - - [11/Oct/2025:21:54:27 +0300] "GET / HTTP/1.1" 200 1189 "-" "Wget/1.25.0" 52198 +192.168.0.114 - - [11/Oct/2025:21:54:45 +0300] "GET /settings HTTP/1.1" 200 7526 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 52041 +192.168.0.114 - - [11/Oct/2025:21:54:45 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 13844 +192.168.0.114 - - [11/Oct/2025:21:54:45 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28824 +192.168.0.114 - - [11/Oct/2025:21:54:45 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28843 +192.168.0.114 - - [11/Oct/2025:21:54:45 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28905 +192.168.0.114 - - [11/Oct/2025:21:55:15 +0300] "POST /create_user HTTP/1.1" 302 205 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 14915 +192.168.0.114 - - [11/Oct/2025:21:55:15 +0300] "GET /settings HTTP/1.1" 200 8101 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 57417 +192.168.0.114 - - [11/Oct/2025:21:55:15 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2648 +192.168.0.114 - - [11/Oct/2025:21:55:15 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3406 +192.168.0.114 - - [11/Oct/2025:21:55:15 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 29402 +192.168.0.114 - - [11/Oct/2025:21:55:15 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 29573 +192.168.0.114 - - [11/Oct/2025:21:55:51 +0300] "POST /create_user HTTP/1.1" 302 205 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 15335 +192.168.0.114 - - [11/Oct/2025:21:55:51 +0300] "GET /settings HTTP/1.1" 200 8603 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 74762 +192.168.0.114 - - [11/Oct/2025:21:55:51 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2530 +192.168.0.114 - - [11/Oct/2025:21:55:51 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2964 +192.168.0.114 - - [11/Oct/2025:21:55:51 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 14047 +192.168.0.114 - - [11/Oct/2025:21:55:51 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28996 +192.168.0.114 - - [11/Oct/2025:21:56:09 +0300] "POST /create_user HTTP/1.1" 302 205 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 15124 +192.168.0.114 - - [11/Oct/2025:21:56:09 +0300] "GET /settings HTTP/1.1" 200 9105 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 57317 +192.168.0.114 - - [11/Oct/2025:21:56:09 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2372 +192.168.0.114 - - [11/Oct/2025:21:56:09 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2327 +192.168.0.114 - - [11/Oct/2025:21:56:09 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2496 +192.168.0.114 - - [11/Oct/2025:21:56:09 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2446 +192.168.0.114 - - [11/Oct/2025:21:56:31 +0300] "GET /dashboard HTTP/1.1" 200 2527 "http://192.168.0.205:8781/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 40192 +192.168.0.114 - - [11/Oct/2025:21:56:31 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2419 +192.168.0.114 - - [11/Oct/2025:21:56:31 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2488 +192.168.0.114 - - [11/Oct/2025:21:56:31 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2535 +192.168.0.114 - - [11/Oct/2025:21:56:31 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28861 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET /logout HTTP/1.1" 302 189 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3949 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET / HTTP/1.1" 200 1189 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 39010 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2368 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET /static/css/login.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2249 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2304 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2436 +192.168.0.114 - - [11/Oct/2025:21:56:35 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2435 +192.168.0.114 - - [11/Oct/2025:21:56:50 +0300] "POST / HTTP/1.1" 302 207 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10225 +192.168.0.114 - - [11/Oct/2025:21:56:50 +0300] "GET /dashboard HTTP/1.1" 200 2527 "http://192.168.0.205:8781/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9905 +192.168.0.114 - - [11/Oct/2025:21:56:50 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2470 +192.168.0.114 - - [11/Oct/2025:21:56:50 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2325 +192.168.0.114 - - [11/Oct/2025:21:56:50 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3243 +192.168.0.114 - - [11/Oct/2025:21:56:50 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2667 +192.168.0.114 - - [11/Oct/2025:21:56:57 +0300] "GET /main_scan HTTP/1.1" 200 1981 "http://192.168.0.205:8781/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7045 +192.168.0.114 - - [11/Oct/2025:21:56:57 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2428 +192.168.0.114 - - [11/Oct/2025:21:56:57 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2313 +192.168.0.114 - - [11/Oct/2025:21:56:57 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2307 +192.168.0.114 - - [11/Oct/2025:21:56:57 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6148 +192.168.0.114 - - [11/Oct/2025:21:56:59 +0300] "GET /fg_scan HTTP/1.1" 200 18932 "http://192.168.0.205:8781/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 26981 +192.168.0.114 - - [11/Oct/2025:21:56:59 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2432 +192.168.0.114 - - [11/Oct/2025:21:56:59 +0300] "GET /static/css/scan.css HTTP/1.1" 200 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2911 +192.168.0.114 - - [11/Oct/2025:21:56:59 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2645 +192.168.0.114 - - [11/Oct/2025:21:56:59 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2875 +192.168.0.114 - - [11/Oct/2025:21:56:59 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3597 +192.168.0.114 - - [11/Oct/2025:21:57:19 +0300] "POST /fg_scan HTTP/1.1" 200 18932 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 35270 +192.168.0.114 - - [11/Oct/2025:21:57:19 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2363 +192.168.0.114 - - [11/Oct/2025:21:57:19 +0300] "GET /static/css/scan.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2354 +192.168.0.114 - - [11/Oct/2025:21:57:19 +0300] "GET /static/script.js HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2353 +192.168.0.114 - - [11/Oct/2025:21:57:19 +0300] "GET /static/style.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2227 +192.168.0.114 - - [11/Oct/2025:21:57:19 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "http://192.168.0.205:8781/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2364 diff --git a/logs/error.log b/logs/error.log new file mode 100644 index 0000000..62f0524 --- /dev/null +++ b/logs/error.log @@ -0,0 +1,54 @@ +[2025-10-11 21:52:09 +0300] [11218] [INFO] Starting gunicorn 23.0.0 +[2025-10-11 21:52:09 +0300] [11218] [ERROR] Connection in use: ('0.0.0.0', 8781) +[2025-10-11 21:52:09 +0300] [11218] [ERROR] connection to ('0.0.0.0', 8781) failed: [Errno 98] Address already in use +[2025-10-11 21:52:10 +0300] [11218] [ERROR] Connection in use: ('0.0.0.0', 8781) +[2025-10-11 21:52:10 +0300] [11218] [ERROR] connection to ('0.0.0.0', 8781) failed: [Errno 98] Address already in use +[2025-10-11 21:52:11 +0300] [11218] [ERROR] Connection in use: ('0.0.0.0', 8781) +[2025-10-11 21:52:11 +0300] [11218] [ERROR] connection to ('0.0.0.0', 8781) failed: [Errno 98] Address already in use +[2025-10-11 21:52:12 +0300] [11218] [ERROR] Connection in use: ('0.0.0.0', 8781) +[2025-10-11 21:52:12 +0300] [11218] [ERROR] connection to ('0.0.0.0', 8781) failed: [Errno 98] Address already in use +[2025-10-11 21:52:13 +0300] [11218] [ERROR] Connection in use: ('0.0.0.0', 8781) +[2025-10-11 21:52:13 +0300] [11218] [ERROR] connection to ('0.0.0.0', 8781) failed: [Errno 98] Address already in use +[2025-10-11 21:52:14 +0300] [11218] [ERROR] Can't connect to ('0.0.0.0', 8781) +[2025-10-11 21:54:00 +0300] [11502] [INFO] Starting gunicorn 23.0.0 +[2025-10-11 21:54:00 +0300] [11502] [INFO] Listening at: http://0.0.0.0:8781 (11502) +[2025-10-11 21:54:00 +0300] [11502] [INFO] Using worker: sync +[2025-10-11 21:54:00 +0300] [11502] [INFO] Trasabilitate Application server is ready. Listening on: [('0.0.0.0', 8781)] +[2025-10-11 21:54:00 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:00 +0300] [11519] [INFO] Booting worker with pid: 11519 +[2025-10-11 21:54:00 +0300] [11519] [INFO] Worker spawned (pid: 11519) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11526] [INFO] Booting worker with pid: 11526 +[2025-10-11 21:54:01 +0300] [11526] [INFO] Worker spawned (pid: 11526) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11527] [INFO] Booting worker with pid: 11527 +[2025-10-11 21:54:01 +0300] [11527] [INFO] Worker spawned (pid: 11527) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11528] [INFO] Booting worker with pid: 11528 +[2025-10-11 21:54:01 +0300] [11528] [INFO] Worker spawned (pid: 11528) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11529] [INFO] Booting worker with pid: 11529 +[2025-10-11 21:54:01 +0300] [11529] [INFO] Worker spawned (pid: 11529) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11530] [INFO] Booting worker with pid: 11530 +[2025-10-11 21:54:01 +0300] [11530] [INFO] Worker spawned (pid: 11530) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11531] [INFO] Booting worker with pid: 11531 +[2025-10-11 21:54:01 +0300] [11531] [INFO] Worker spawned (pid: 11531) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11532] [INFO] Booting worker with pid: 11532 +[2025-10-11 21:54:01 +0300] [11532] [INFO] Worker spawned (pid: 11532) +[2025-10-11 21:54:01 +0300] [11502] [INFO] Worker spawned (pid: [booting]) +[2025-10-11 21:54:01 +0300] [11533] [INFO] Booting worker with pid: 11533 +[2025-10-11 21:54:01 +0300] [11533] [INFO] Worker spawned (pid: 11533) +[2025-10-11 21:58:19 +0300] [11502] [INFO] Handling signal: term +[2025-10-11 21:58:19 +0300] [11519] [INFO] Worker exiting (pid: 11519) +[2025-10-11 21:58:19 +0300] [11526] [INFO] Worker exiting (pid: 11526) +[2025-10-11 21:58:19 +0300] [11527] [INFO] Worker exiting (pid: 11527) +[2025-10-11 21:58:19 +0300] [11533] [INFO] Worker exiting (pid: 11533) +[2025-10-11 21:58:19 +0300] [11528] [INFO] Worker exiting (pid: 11528) +[2025-10-11 21:58:19 +0300] [11529] [INFO] Worker exiting (pid: 11529) +[2025-10-11 21:58:19 +0300] [11530] [INFO] Worker exiting (pid: 11530) +[2025-10-11 21:58:19 +0300] [11531] [INFO] Worker exiting (pid: 11531) +[2025-10-11 21:58:19 +0300] [11532] [INFO] Worker exiting (pid: 11532) +[2025-10-11 21:58:20 +0300] [11502] [INFO] Shutting down: Master diff --git a/py_app/app/print_module.py b/py_app/app/print_module.py index 0052b3d..903838c 100755 --- a/py_app/app/print_module.py +++ b/py_app/app/print_module.py @@ -34,9 +34,9 @@ def get_unprinted_orders_data(limit=100): # Use printed_labels column cursor.execute(""" SELECT id, comanda_productie, cod_articol, descr_com_prod, cantitate, - data_livrare, dimensiune, com_achiz_client, nr_linie_com_client, customer_name, + com_achiz_client, nr_linie_com_client, customer_name, customer_article_number, open_for_order, line_number, - printed_labels, created_at, updated_at + created_at, updated_at, printed_labels, data_livrare, dimensiune FROM order_for_labels WHERE printed_labels != 1 ORDER BY created_at DESC @@ -46,7 +46,7 @@ def get_unprinted_orders_data(limit=100): # Fallback: get all orders if no printed_labels column cursor.execute(""" SELECT id, comanda_productie, cod_articol, descr_com_prod, cantitate, - data_livrare, dimensiune, com_achiz_client, nr_linie_com_client, customer_name, + com_achiz_client, nr_linie_com_client, customer_name, customer_article_number, open_for_order, line_number, created_at, updated_at FROM order_for_labels @@ -63,17 +63,17 @@ def get_unprinted_orders_data(limit=100): 'cod_articol': row[2], 'descr_com_prod': row[3], 'cantitate': row[4], - 'data_livrare': row[5], - 'dimensiune': row[6], - 'com_achiz_client': row[7], - 'nr_linie_com_client': row[8], - 'customer_name': row[9], - 'customer_article_number': row[10], - 'open_for_order': row[11], - 'line_number': row[12], + 'com_achiz_client': row[5], + 'nr_linie_com_client': row[6], + 'customer_name': row[7], + 'customer_article_number': row[8], + 'open_for_order': row[9], + 'line_number': row[10], + 'created_at': row[11], + 'updated_at': row[12], 'printed_labels': row[13], - 'created_at': row[14], - 'updated_at': row[15] + 'data_livrare': row[14] or '-', + 'dimensiune': row[15] or '-' }) else: orders.append({ @@ -82,17 +82,18 @@ def get_unprinted_orders_data(limit=100): 'cod_articol': row[2], 'descr_com_prod': row[3], 'cantitate': row[4], - 'data_livrare': row[5], - 'dimensiune': row[6], - 'com_achiz_client': row[7], - 'nr_linie_com_client': row[8], - 'customer_name': row[9], - 'customer_article_number': row[10], - 'open_for_order': row[11], - 'line_number': row[12], - 'printed_labels': 0, # Default to not printed - 'created_at': row[13], - 'updated_at': row[14] + 'com_achiz_client': row[5], + 'nr_linie_com_client': row[6], + 'customer_name': row[7], + 'customer_article_number': row[8], + 'open_for_order': row[9], + 'line_number': row[10], + 'created_at': row[11], + 'updated_at': row[12], + # Add default values for missing columns + 'data_livrare': '-', + 'dimensiune': '-', + 'printed_labels': 0 }) conn.close() diff --git a/py_app/app/routes.py b/py_app/app/routes.py index d93f99d..1d82037 100755 --- a/py_app/app/routes.py +++ b/py_app/app/routes.py @@ -242,27 +242,42 @@ def scan(): conn = get_db_connection() cursor = conn.cursor() - # Check if the CP_full_code already exists - cursor.execute("SELECT Id FROM scan1_orders WHERE CP_full_code = ?", (cp_code,)) - existing_entry = cursor.fetchone() - - if existing_entry: - # Update the existing entry - update_query = """ - UPDATE scan1_orders - SET operator_code = ?, OC1_code = ?, OC2_code = ?, quality_code = ?, date = ?, time = ? - WHERE CP_full_code = ? - """ - cursor.execute(update_query, (operator_code, oc1_code, oc2_code, defect_code, date, time, cp_code)) - flash('Existing entry updated successfully.') + # Always insert a new entry - each scan is a separate record + insert_query = """ + INSERT INTO scan1_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) + VALUES (%s, %s, %s, %s, %s, %s, %s) + """ + cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time)) + + # Get the CP_base_code (first 10 characters of CP_full_code) + cp_base_code = cp_code[:10] + + # Count approved quantities (quality_code = 0) for this CP_base_code + cursor.execute(""" + SELECT COUNT(*) FROM scan1_orders + WHERE CP_base_code = %s AND quality_code = 0 + """, (cp_base_code,)) + approved_count = cursor.fetchone()[0] + + # Count rejected quantities (quality_code != 0) for this CP_base_code + cursor.execute(""" + SELECT COUNT(*) FROM scan1_orders + WHERE CP_base_code = %s AND quality_code != 0 + """, (cp_base_code,)) + rejected_count = cursor.fetchone()[0] + + # Update all records with the same CP_base_code with new quantities + cursor.execute(""" + UPDATE scan1_orders + SET approved_quantity = %s, rejected_quantity = %s + WHERE CP_base_code = %s + """, (approved_count, rejected_count, cp_base_code)) + + # Flash appropriate message + if int(defect_code) == 0: + flash(f'✅ APPROVED scan recorded for {cp_code}. Total approved: {approved_count}') else: - # Insert a new entry - insert_query = """ - INSERT INTO scan1_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) - VALUES (?, ?, ?, ?, ?, ?, ?) - """ - cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time)) - flash('New entry inserted successfully.') + flash(f'❌ REJECTED scan recorded for {cp_code} (defect: {defect_code}). Total rejected: {rejected_count}') # Commit the transaction conn.commit() @@ -278,7 +293,7 @@ def scan(): conn = get_db_connection() cursor = conn.cursor() cursor.execute(""" - SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity + SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity FROM scan1_orders ORDER BY Id DESC LIMIT 15 @@ -321,27 +336,42 @@ def fg_scan(): conn = get_db_connection() cursor = conn.cursor() - # Check if the CP_full_code already exists in scanfg_orders - cursor.execute("SELECT Id FROM scanfg_orders WHERE CP_full_code = ?", (cp_code,)) - existing_entry = cursor.fetchone() - - if existing_entry: - # Update the existing entry - update_query = """ - UPDATE scanfg_orders - SET operator_code = ?, OC1_code = ?, OC2_code = ?, quality_code = ?, date = ?, time = ? - WHERE CP_full_code = ? - """ - cursor.execute(update_query, (operator_code, oc1_code, oc2_code, defect_code, date, time, cp_code)) - flash('Existing entry updated successfully.') + # Always insert a new entry - each scan is a separate record + insert_query = """ + INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) + VALUES (%s, %s, %s, %s, %s, %s, %s) + """ + cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time)) + + # Get the CP_base_code (first 10 characters of CP_full_code) + cp_base_code = cp_code[:10] + + # Count approved quantities (quality_code = 0) for this CP_base_code + cursor.execute(""" + SELECT COUNT(*) FROM scanfg_orders + WHERE CP_base_code = %s AND quality_code = 0 + """, (cp_base_code,)) + approved_count = cursor.fetchone()[0] + + # Count rejected quantities (quality_code != 0) for this CP_base_code + cursor.execute(""" + SELECT COUNT(*) FROM scanfg_orders + WHERE CP_base_code = %s AND quality_code != 0 + """, (cp_base_code,)) + rejected_count = cursor.fetchone()[0] + + # Update all records with the same CP_base_code with new quantities + cursor.execute(""" + UPDATE scanfg_orders + SET approved_quantity = %s, rejected_quantity = %s + WHERE CP_base_code = %s + """, (approved_count, rejected_count, cp_base_code)) + + # Flash appropriate message + if int(defect_code) == 0: + flash(f'✅ APPROVED scan recorded for {cp_code}. Total approved: {approved_count}') else: - # Insert a new entry - insert_query = """ - INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time) - VALUES (?, ?, ?, ?, ?, ?, ?) - """ - cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time)) - flash('New entry inserted successfully.') + flash(f'❌ REJECTED scan recorded for {cp_code} (defect: {defect_code}). Total rejected: {rejected_count}') # Commit the transaction conn.commit() @@ -357,7 +387,7 @@ def fg_scan(): conn = get_db_connection() cursor = conn.cursor() cursor.execute(""" - SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity + SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity FROM scanfg_orders ORDER BY Id DESC LIMIT 15 @@ -1036,13 +1066,273 @@ def etichete(): return redirect(url_for('main.dashboard')) return render_template('main_page_etichete.html') -@bp.route('/upload_data') +@bp.route('/upload_data', methods=['GET', 'POST']) def upload_data(): + if request.method == 'POST': + action = request.form.get('action', 'preview') + + if action == 'preview': + # Handle file upload and show preview + if 'file' not in request.files: + flash('No file selected', 'error') + return redirect(request.url) + + file = request.files['file'] + if file.filename == '': + flash('No file selected', 'error') + return redirect(request.url) + + if file and file.filename.lower().endswith('.csv'): + try: + # Read CSV file + import csv + import io + + # Read the file content + stream = io.StringIO(file.stream.read().decode("UTF8"), newline=None) + csv_input = csv.DictReader(stream) + + # Convert to list for preview + preview_data = [] + headers = [] + + for i, row in enumerate(csv_input): + if i == 0: + headers = list(row.keys()) + if i < 10: # Show only first 10 rows for preview + preview_data.append(row) + else: + break + + # Store the full file content in session for later processing + file.stream.seek(0) # Reset file pointer + session['csv_content'] = file.stream.read().decode("UTF8") + session['csv_filename'] = file.filename + + return render_template('upload_orders.html', + preview_data=preview_data, + headers=headers, + show_preview=True, + filename=file.filename) + + except Exception as e: + flash(f'Error reading CSV file: {str(e)}', 'error') + return redirect(request.url) + else: + flash('Please upload a CSV file', 'error') + return redirect(request.url) + + elif action == 'save': + # Save the data to database + if 'csv_content' not in session: + flash('No data to save. Please upload a file first.', 'error') + return redirect(request.url) + + try: + import csv + import io + + print(f"DEBUG: Starting CSV upload processing...") + + # Read the CSV content from session + stream = io.StringIO(session['csv_content'], newline=None) + csv_input = csv.DictReader(stream) + + # Connect to database + conn = get_db_connection() + cursor = conn.cursor() + + inserted_count = 0 + error_count = 0 + errors = [] + + print(f"DEBUG: Connected to database, processing rows...") + + # Process each row + for index, row in enumerate(csv_input): + try: + print(f"DEBUG: Processing row {index + 1}: {row}") + + # Extract data from CSV row with proper column mapping + comanda_productie = str(row.get('comanda_productie', row.get('Comanda Productie', row.get('Order Number', '')))).strip() + cod_articol = str(row.get('cod_articol', row.get('Cod Articol', row.get('Article Code', '')))).strip() + descr_com_prod = str(row.get('descr_com_prod', row.get('Descr. Com. Prod', row.get('Descr Com Prod', row.get('Description', ''))))).strip() + cantitate = int(float(row.get('cantitate', row.get('Cantitate', row.get('Quantity', 0))))) + com_achiz_client = str(row.get('com_achiz_client', row.get('Com.Achiz.Client', row.get('Com Achiz Client', '')))).strip() + nr_linie_com_client = row.get('nr_linie_com_client', row.get('Nr. Linie com. Client', row.get('Nr Linie Com Client', ''))) + customer_name = str(row.get('customer_name', row.get('Customer Name', ''))).strip() + customer_article_number = str(row.get('customer_article_number', row.get('Customer Article Number', ''))).strip() + open_for_order = str(row.get('open_for_order', row.get('Open for order', row.get('Open For Order', '')))).strip() + line_number = row.get('line_number', row.get('Line ', row.get('Line Number', ''))) + data_livrare = str(row.get('data_livrare', row.get('DataLivrare', row.get('Data Livrare', '')))).strip() + dimensiune = str(row.get('dimensiune', row.get('Dimensiune', ''))).strip() + + print(f"DEBUG: Extracted data - comanda_productie: {comanda_productie}, descr_com_prod: {descr_com_prod}, cantitate: {cantitate}") + + # Convert empty strings to None for integer fields + nr_linie_com_client = int(nr_linie_com_client) if nr_linie_com_client and str(nr_linie_com_client).strip() else None + line_number = int(line_number) if line_number and str(line_number).strip() else None + + # Convert empty string to None for date field + if data_livrare: + try: + # Parse date from various formats (9/23/2023, 23/9/2023, 2023-09-23, etc.) + from datetime import datetime + # Try different date formats + date_formats = ['%m/%d/%Y', '%d/%m/%Y', '%Y-%m-%d', '%m-%d-%Y', '%d-%m-%Y'] + parsed_date = None + for fmt in date_formats: + try: + parsed_date = datetime.strptime(data_livrare, fmt) + break + except ValueError: + continue + + if parsed_date: + data_livrare = parsed_date.strftime('%Y-%m-%d') # MySQL date format + print(f"DEBUG: Parsed date: {data_livrare}") + else: + print(f"DEBUG: Could not parse date: {data_livrare}, setting to None") + data_livrare = None + except Exception as date_error: + print(f"DEBUG: Date parsing error: {date_error}") + data_livrare = None + else: + data_livrare = None + + dimensiune = dimensiune if dimensiune else None + + print(f"DEBUG: Final data before insert - nr_linie: {nr_linie_com_client}, line_number: {line_number}, data_livrare: {data_livrare}") + + if comanda_productie and descr_com_prod and cantitate > 0: + # Insert into order_for_labels table with correct columns + print(f"DEBUG: Inserting order: {comanda_productie}") + try: + cursor.execute(""" + INSERT INTO order_for_labels ( + comanda_productie, cod_articol, descr_com_prod, cantitate, + com_achiz_client, nr_linie_com_client, customer_name, + customer_article_number, open_for_order, line_number, + data_livrare, dimensiune, printed_labels + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 0) + """, (comanda_productie, cod_articol, descr_com_prod, cantitate, + com_achiz_client, nr_linie_com_client, customer_name, + customer_article_number, open_for_order, line_number, + data_livrare, dimensiune)) + inserted_count += 1 + print(f"DEBUG: Successfully inserted order: {comanda_productie}") + except Exception as insert_error: + print(f"DEBUG: Database insert error for {comanda_productie}: {insert_error}") + errors.append(f"Row {index + 1}: Database error - {str(insert_error)}") + error_count += 1 + else: + missing_fields = [] + if not comanda_productie: + missing_fields.append("comanda_productie") + if not descr_com_prod: + missing_fields.append("descr_com_prod") + if cantitate <= 0: + missing_fields.append("cantitate (must be > 0)") + errors.append(f"Row {index + 1}: Missing required fields: {', '.join(missing_fields)}") + error_count += 1 + except ValueError as e: + errors.append(f"Row {index + 1}: Invalid quantity value") + error_count += 1 + except Exception as e: + errors.append(f"Row {index + 1}: {str(e)}") + error_count += 1 + continue + + # Commit the transaction + conn.commit() + conn.close() + + print(f"DEBUG: Committed {inserted_count} records to database") + + # Clear session data + session.pop('csv_content', None) + session.pop('csv_filename', None) + + # Show results + if error_count > 0: + flash(f'Upload completed: {inserted_count} orders saved, {error_count} errors', 'warning') + for error in errors[:5]: # Show only first 5 errors + flash(error, 'error') + if len(errors) > 5: + flash(f'... and {len(errors) - 5} more errors', 'error') + else: + flash(f'Successfully uploaded {inserted_count} orders for labels', 'success') + + except Exception as e: + flash(f'Error processing data: {str(e)}', 'error') + + return redirect(url_for('main.upload_data')) + + # GET request - show the upload form return render_template('upload_orders.html') +@bp.route('/upload_orders') +def upload_orders(): + """Redirect to upload_data for compatibility""" + return redirect(url_for('main.upload_data')) + @bp.route('/print_module') def print_module(): - return render_template('print_module.html') + try: + # Get unprinted orders data + orders_data = get_unprinted_orders_data(limit=100) + return render_template('print_module.html', orders=orders_data) + except Exception as e: + print(f"Error loading print module data: {e}") + flash(f"Error loading orders: {e}", 'error') + return render_template('print_module.html', orders=[]) + +@bp.route('/view_orders') +def view_orders(): + """View all orders in a table format""" + try: + # Get all orders data (not just unprinted) + conn = get_db_connection() + cursor = conn.cursor() + + cursor.execute(""" + SELECT id, comanda_productie, cod_articol, descr_com_prod, cantitate, + com_achiz_client, nr_linie_com_client, customer_name, + customer_article_number, open_for_order, line_number, + created_at, updated_at, printed_labels, data_livrare, dimensiune + FROM order_for_labels + ORDER BY created_at DESC + LIMIT 500 + """) + + orders_data = [] + for row in cursor.fetchall(): + orders_data.append({ + 'id': row[0], + 'comanda_productie': row[1], + 'cod_articol': row[2], + 'descr_com_prod': row[3], + 'cantitate': row[4], + 'com_achiz_client': row[5], + 'nr_linie_com_client': row[6], + 'customer_name': row[7], + 'customer_article_number': row[8], + 'open_for_order': row[9], + 'line_number': row[10], + 'created_at': row[11], + 'updated_at': row[12], + 'printed_labels': row[13], + 'data_livrare': row[14] or '-', + 'dimensiune': row[15] or '-' + }) + + conn.close() + return render_template('view_orders.html', orders=orders_data) + + except Exception as e: + print(f"Error loading view orders data: {e}") + flash(f"Error loading orders: {e}", 'error') + return render_template('view_orders.html', orders=[]) import secrets diff --git a/py_app/app/templates/fg_scan.html b/py_app/app/templates/fg_scan.html index ab88ad9..2920196 100644 --- a/py_app/app/templates/fg_scan.html +++ b/py_app/app/templates/fg_scan.html @@ -23,6 +23,80 @@ document.addEventListener('DOMContentLoaded', function() { const defectCodeInput = document.getElementById('defect_code'); const form = document.getElementById('fg-scan-form'); + // Restore saved operator code from localStorage (only Quality Operator Code) + const savedOperatorCode = localStorage.getItem('fg_scan_operator_code'); + + if (savedOperatorCode) { + operatorCodeInput.value = savedOperatorCode; + } + + // Check if we need to clear fields after a successful submission + const shouldClearAfterSubmit = localStorage.getItem('fg_scan_clear_after_submit'); + if (shouldClearAfterSubmit === 'true') { + // Clear the flag + localStorage.removeItem('fg_scan_clear_after_submit'); + localStorage.removeItem('fg_scan_last_cp'); + localStorage.removeItem('fg_scan_last_defect'); + + // Clear CP code, OC1, OC2, and defect code for next scan + cpCodeInput.value = ''; + oc1CodeInput.value = ''; + oc2CodeInput.value = ''; + defectCodeInput.value = ''; + + // Show success indicator + setTimeout(function() { + // Focus on CP code field for next scan + cpCodeInput.focus(); + + // Add visual feedback + const successIndicator = document.createElement('div'); + successIndicator.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: #4CAF50; + color: white; + padding: 10px 20px; + border-radius: 5px; + z-index: 1000; + box-shadow: 0 2px 10px rgba(0,0,0,0.2); + font-weight: bold; + `; + successIndicator.textContent = '✅ Scan recorded! Ready for next scan'; + document.body.appendChild(successIndicator); + + // Remove success indicator after 3 seconds + setTimeout(function() { + if (successIndicator.parentNode) { + successIndicator.parentNode.removeChild(successIndicator); + } + }, 3000); + }, 100); + } + + // Focus on the first empty required field (only if not clearing after submit) + if (shouldClearAfterSubmit !== 'true') { + if (!operatorCodeInput.value) { + operatorCodeInput.focus(); + } else if (!oc1CodeInput.value) { + oc1CodeInput.focus(); + } else if (!oc2CodeInput.value) { + oc2CodeInput.focus(); + } else if (!cpCodeInput.value) { + cpCodeInput.focus(); + } else { + defectCodeInput.focus(); + } + } + + // Save operator codes to localStorage when they change (only Quality Operator Code) + operatorCodeInput.addEventListener('input', function() { + if (this.value.startsWith('OP') && this.value.length >= 3) { + localStorage.setItem('fg_scan_operator_code', this.value); + } + }); + // Create error message element for operator code const operatorErrorMessage = document.createElement('div'); operatorErrorMessage.className = 'error-message'; @@ -338,6 +412,11 @@ document.addEventListener('DOMContentLoaded', function() { const seconds = String(now.getSeconds()).padStart(2, '0'); timeInput.value = `${hours}:${minutes}:${seconds}`; + // Save current CP code and defect code to localStorage for clearing after reload + localStorage.setItem('fg_scan_clear_after_submit', 'true'); + localStorage.setItem('fg_scan_last_cp', cpCodeInput.value); + localStorage.setItem('fg_scan_last_defect', defectCodeInput.value); + // Submit the form form.submit(); } @@ -399,6 +478,27 @@ document.addEventListener('DOMContentLoaded', function() { } } }); + + // Add functionality for clear saved codes button + const clearSavedBtn = document.getElementById('clear-saved-btn'); + clearSavedBtn.addEventListener('click', function() { + if (confirm('Clear saved Quality Operator code? You will need to re-enter it.')) { + // Clear localStorage (only Quality Operator Code) + localStorage.removeItem('fg_scan_operator_code'); + localStorage.removeItem('fg_scan_clear_after_submit'); + localStorage.removeItem('fg_scan_last_cp'); + localStorage.removeItem('fg_scan_last_defect'); + + // Clear Quality Operator Code field only + operatorCodeInput.value = ''; + + // Focus on operator code field + operatorCodeInput.focus(); + + // Show confirmation + alert('✅ Saved Quality Operator code cleared! Please re-enter your operator code.'); + } + }); }); {% endblock %} @@ -430,6 +530,7 @@ document.addEventListener('DOMContentLoaded', function() { + diff --git a/py_app/app/templates/main_page_etichete.html b/py_app/app/templates/main_page_etichete.html index 25083fc..7e9383d 100755 --- a/py_app/app/templates/main_page_etichete.html +++ b/py_app/app/templates/main_page_etichete.html @@ -15,7 +15,7 @@

Upload new orders or view existing orders and manage label data for printing.

Upload Orders - View Orders + View Orders
diff --git a/py_app/app/templates/print_module.html b/py_app/app/templates/print_module.html index bd64342..dbdb37e 100755 --- a/py_app/app/templates/print_module.html +++ b/py_app/app/templates/print_module.html @@ -10,8 +10,9 @@ /* Enhanced table styling */ .card.scan-table-card table.print-module-table.scan-table thead th { - border-bottom: 2px solid #dee2e6 !important; - background-color: #f8f9fa !important; + border-bottom: 2px solid var(--app-border-color, #dee2e6) !important; + background-color: var(--app-table-header-bg, #2a3441) !important; + color: var(--app-text-color, #ffffff) !important; padding: 0.25rem 0.4rem !important; text-align: left !important; font-weight: 600 !important; @@ -22,13 +23,21 @@ .card.scan-table-card table.print-module-table.scan-table { width: 100% !important; border-collapse: collapse !important; + background-color: var(--app-card-bg, #2a3441) !important; } .card.scan-table-card table.print-module-table.scan-table tbody tr:hover td { - background-color: #f8f9fa !important; + background-color: var(--app-hover-bg, #3a4451) !important; cursor: pointer !important; } +.card.scan-table-card table.print-module-table.scan-table tbody td { + background-color: var(--app-card-bg, #2a3441) !important; + color: var(--app-text-color, #ffffff) !important; + border: 1px solid var(--app-border-color, #495057) !important; + padding: 0.25rem 0.4rem !important; +} + .card.scan-table-card table.print-module-table.scan-table tbody tr.selected td { background-color: #007bff !important; color: white !important; @@ -140,13 +149,13 @@ - -
+ +
- + - -
+ +
@@ -156,8 +165,8 @@ - -
+ +
@@ -475,10 +484,12 @@ function updateLabelPreview(order) { JsBarcode("#barcode-display", horizontalBarcodeData, { format: "CODE128", - width: 2, + width: 1.2, height: 40, displayValue: false, - margin: 2 + margin: 0, + fontSize: 0, + textMargin: 0 }); console.log('✅ Horizontal barcode generated successfully'); } catch (e) { diff --git a/py_app/app/templates/scan.html b/py_app/app/templates/scan.html index 3d32fef..eae42b0 100755 --- a/py_app/app/templates/scan.html +++ b/py_app/app/templates/scan.html @@ -22,6 +22,74 @@ document.addEventListener('DOMContentLoaded', function() { const defectCodeInput = document.getElementById('defect_code'); const form = document.querySelector('.form-centered'); + // Load saved operator codes from localStorage (only Quality Operator Code) + function loadSavedCodes() { + const savedOperatorCode = localStorage.getItem('scan_operator_code'); + + if (savedOperatorCode) { + operatorCodeInput.value = savedOperatorCode; + } + } + + // Save operator codes to localStorage (only Quality Operator Code) + function saveCodes() { + if (operatorCodeInput.value.startsWith('OP')) { + localStorage.setItem('scan_operator_code', operatorCodeInput.value); + } + } + + // Clear saved codes from localStorage (only Quality Operator Code) + function clearSavedCodes() { + localStorage.removeItem('scan_operator_code'); + operatorCodeInput.value = ''; + showSuccessMessage('Quality Operator code cleared!'); + operatorCodeInput.focus(); + } + + // Show success message + function showSuccessMessage(message) { + const successDiv = document.createElement('div'); + successDiv.className = 'success-message'; + successDiv.textContent = message; + successDiv.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: #4CAF50; + color: white; + padding: 15px 20px; + border-radius: 4px; + z-index: 1000; + font-weight: bold; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + `; + document.body.appendChild(successDiv); + + setTimeout(() => { + if (document.body.contains(successDiv)) { + document.body.removeChild(successDiv); + } + }, 3000); + } + + // Load saved codes on page load + loadSavedCodes(); + + // Focus on the first empty field + setTimeout(() => { + if (!operatorCodeInput.value) { + operatorCodeInput.focus(); + } else if (!cpCodeInput.value) { + cpCodeInput.focus(); + } else if (!oc1CodeInput.value) { + oc1CodeInput.focus(); + } else if (!oc2CodeInput.value) { + oc2CodeInput.focus(); + } else { + defectCodeInput.focus(); + } + }, 100); + // Create error message element for operator code const operatorErrorMessage = document.createElement('div'); operatorErrorMessage.className = 'error-message'; @@ -333,8 +401,21 @@ document.addEventListener('DOMContentLoaded', function() { const seconds = String(now.getSeconds()).padStart(2, '0'); timeInput.value = `${hours}:${minutes}:${seconds}`; + // Save operator codes before submitting + saveCodes(); + // Submit the form form.submit(); + + // Clear CP, OC1, OC2, and defect code fields after successful submission + setTimeout(() => { + cpCodeInput.value = ''; + oc1CodeInput.value = ''; + oc2CodeInput.value = ''; + defectCodeInput.value = ''; + showSuccessMessage('Scan submitted successfully!'); + cpCodeInput.focus(); + }, 100); } }); @@ -425,6 +506,7 @@ document.addEventListener('DOMContentLoaded', function() { +
diff --git a/py_app/app/templates/upload_orders.html b/py_app/app/templates/upload_orders.html index 589b904..3d3566a 100755 --- a/py_app/app/templates/upload_orders.html +++ b/py_app/app/templates/upload_orders.html @@ -82,15 +82,35 @@ table.view-orders-table.scan-table tbody tr:hover td {

Upload Order Data for Labels

{% endif %}
- - {% if leftover_description %} - - {% elif not orders %} -
- + {% if show_preview %} + + +
+

+ Showing first 10 rows. Review the data below and click "Save to Database" to confirm. +

+ + Cancel {% else %} -
- + + + +
+ + + +
+
Expected CSV Format
+

Your CSV file should contain columns such as:

+
    +
  • order_number - The order/production number
  • +
  • quantity - Number of items
  • +
  • warehouse_location - Storage location
  • +
+

+ Column names are case-insensitive and can have variations like "Order Number", "Quantity", "Location", etc. +

+
{% endif %}
@@ -124,108 +144,45 @@ table.view-orders-table.scan-table tbody tr:hover td {
-
- {% if leftover_description %} -

Left over orders

+
+ {% if show_preview %} +

CSV Data Preview - {{ filename }}

+ + + + {% for header in headers %} + + {% endfor %} + + + + {% if preview_data %} + {% for row in preview_data %} + + {% for header in headers %} + + {% endfor %} + + {% endfor %} + {% else %} + + {% endif %} + +
{{ header }}
{{ row.get(header, '') }}
No data to preview
{% else %} -

Preview Table

+

CSV Data Preview

+ + + + + + + + + +
Upload a CSV file to see preview
No CSV file uploaded yet. Use the form above to upload and preview your data.
{% endif %} - - - - - - - - - - - - - - - - - - - - - - {% if orders %} - {% for order in orders %} - {% if order and (order.get('comanda_productie', '') or order.get('descr_com_prod', '')) %} - - - - - - - - - - - - - - - - - - {% if order.error_message %} - - - - {% endif %} - {% endif %} - {% endfor %} - {% else %} - - {% endif %} - -
IDComanda
Productie
Cod
Articol
Descr. Com.
Prod
CantitateData
Livrare
DimensiuneCom.Achiz.
Client
Nr.
Linie
Customer
Name
Customer
Art. Nr.
Open
Order
LinePrintedCreated
{{ order.get('id', '') }}{{ order.get('comanda_productie', '') }}{{ order.get('cod_articol', '-') }}{{ order.get('descr_com_prod', '') }}{{ order.get('cantitate', '') }}{{ order.get('data_livrare', '') }}{{ order.get('dimensiune', '-') }}{{ order.get('com_achiz_client', '-') }}{{ order.get('nr_linie_com_client', '-') }}{{ order.get('customer_name', '-') }}{{ order.get('customer_article_number', '-') }}{{ order.get('open_for_order', '-') }}{{ order.get('line_number', '-') }} - {% if order.get('printed_labels', 0) == 1 %} - ✓ Yes - {% else %} - ✗ No - {% endif %} - {{ order.get('created_at', '-') }}
- Error: {{ order.error_message }} -
No CSV file uploaded yet.
- - {% if validation_errors or validation_warnings %} - {% if not leftover_description %} -
-

Validation Results

- {% if validation_errors %} -
- Errors found: -
    - {% for error in validation_errors %} -
  • {{ error }}
  • - {% endfor %} -
-
- {% endif %} - {% if validation_warnings %} -
- Warnings: -
    - {% for warning in validation_warnings %} -
  • {{ warning }}
  • - {% endfor %} -
-
- {% endif %} -
- {% if report %} -
-

Import Report

-

{{ report }}

-
- {% endif %} - {% endif %} -{% endif %}