Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b87c398977 |
@@ -1,61 +0,0 @@
|
||||
# Git files
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
|
||||
# Virtual environments
|
||||
venv/
|
||||
env/
|
||||
ENV/
|
||||
recticel/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Database
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
!README.md
|
||||
|
||||
# Backup files
|
||||
backup/
|
||||
*.bak
|
||||
*.backup
|
||||
*.old
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Application specific
|
||||
instance/*.db
|
||||
chrome_extension/
|
||||
VS code/
|
||||
tray/
|
||||
|
||||
# Scripts not needed in container
|
||||
*.sh
|
||||
!docker-entrypoint.sh
|
||||
|
||||
# Service files
|
||||
*.service
|
||||
|
||||
# Config that will be generated
|
||||
instance/external_server.conf
|
||||
13
.env.example
@@ -1,13 +0,0 @@
|
||||
# Environment Configuration for Recticel Quality Application
|
||||
# Copy this file to .env and adjust the values as needed
|
||||
|
||||
# Database Configuration
|
||||
MYSQL_ROOT_PASSWORD=rootpassword
|
||||
DB_PORT=3306
|
||||
|
||||
# Application Configuration
|
||||
APP_PORT=8781
|
||||
|
||||
# Initialization Flags (set to "false" after first successful deployment)
|
||||
INIT_DB=true
|
||||
SEED_DB=true
|
||||
15
.gitignore
vendored
@@ -28,19 +28,4 @@ VS code/obj/
|
||||
|
||||
# Backup files
|
||||
*.backup
|
||||
|
||||
# Docker deployment
|
||||
.env
|
||||
*.env
|
||||
!.env.example
|
||||
logs/
|
||||
*.log
|
||||
app.log
|
||||
backup_*.sql
|
||||
instance/external_server.conf
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
.docker/
|
||||
|
||||
*.backup2
|
||||
|
||||
41
Dockerfile
@@ -1,41 +0,0 @@
|
||||
# Dockerfile for Recticel Quality Application
|
||||
FROM python:3.10-slim
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
FLASK_APP=run.py \
|
||||
FLASK_ENV=production
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
default-libmysqlclient-dev \
|
||||
pkg-config \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy requirements and install Python dependencies
|
||||
COPY py_app/requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code
|
||||
COPY py_app/ .
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p /app/instance /srv/quality_recticel/logs
|
||||
|
||||
# Create a script to wait for database and initialize
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8781
|
||||
|
||||
# Use the entrypoint script
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
||||
# Run gunicorn
|
||||
CMD ["gunicorn", "--config", "gunicorn.conf.py", "wsgi:application"]
|
||||
93
Makefile
@@ -1,93 +0,0 @@
|
||||
.PHONY: help build up down restart logs logs-web logs-db clean reset shell shell-db status health
|
||||
|
||||
help: ## Show this help message
|
||||
@echo "Recticel Quality Application - Docker Commands"
|
||||
@echo ""
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
build: ## Build the Docker images
|
||||
docker-compose build
|
||||
|
||||
up: ## Start all services
|
||||
docker-compose up -d
|
||||
@echo "✅ Services started. Access the app at http://localhost:8781"
|
||||
@echo "Default login: superadmin / superadmin123"
|
||||
|
||||
down: ## Stop all services
|
||||
docker-compose down
|
||||
|
||||
restart: ## Restart all services
|
||||
docker-compose restart
|
||||
|
||||
logs: ## View logs from all services
|
||||
docker-compose logs -f
|
||||
|
||||
logs-web: ## View logs from web application
|
||||
docker-compose logs -f web
|
||||
|
||||
logs-db: ## View logs from database
|
||||
docker-compose logs -f db
|
||||
|
||||
status: ## Show status of all services
|
||||
docker-compose ps
|
||||
|
||||
health: ## Check health of services
|
||||
@echo "=== Service Health Status ==="
|
||||
@docker inspect recticel-app | grep -A 5 '"Health"' || echo "Web app: Running"
|
||||
@docker inspect recticel-db | grep -A 5 '"Health"' || echo "Database: Running"
|
||||
|
||||
shell: ## Open shell in web application container
|
||||
docker-compose exec web bash
|
||||
|
||||
shell-db: ## Open MariaDB console
|
||||
docker-compose exec db mariadb -u trasabilitate -p trasabilitate
|
||||
|
||||
clean: ## Stop services and remove containers (keeps data)
|
||||
docker-compose down
|
||||
|
||||
reset: ## Complete reset - removes all data including database
|
||||
@echo "⚠️ WARNING: This will delete all data!"
|
||||
@read -p "Are you sure? [y/N] " -n 1 -r; \
|
||||
echo; \
|
||||
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
|
||||
docker-compose down -v; \
|
||||
rm -rf logs/*; \
|
||||
rm -f instance/external_server.conf; \
|
||||
echo "✅ Reset complete"; \
|
||||
fi
|
||||
|
||||
deploy: build up ## Build and deploy (fresh start)
|
||||
@echo "✅ Deployment complete!"
|
||||
@sleep 5
|
||||
@make status
|
||||
|
||||
rebuild: ## Rebuild and restart web application
|
||||
docker-compose up -d --build web
|
||||
|
||||
backup-db: ## Backup database to backup.sql
|
||||
docker-compose exec -T db mariadb-dump -u trasabilitate -pInitial01! trasabilitate > backup_$(shell date +%Y%m%d_%H%M%S).sql
|
||||
@echo "✅ Database backed up"
|
||||
|
||||
restore-db: ## Restore database from backup.sql (provide BACKUP=filename)
|
||||
@if [ -z "$(BACKUP)" ]; then \
|
||||
echo "❌ Usage: make restore-db BACKUP=backup_20231215_120000.sql"; \
|
||||
exit 1; \
|
||||
fi
|
||||
docker-compose exec -T db mariadb -u trasabilitate -pInitial01! trasabilitate < $(BACKUP)
|
||||
@echo "✅ Database restored from $(BACKUP)"
|
||||
|
||||
install: ## Initial installation and setup
|
||||
@echo "=== Installing Recticel Quality Application ==="
|
||||
@if [ ! -f .env ]; then \
|
||||
cp .env.example .env; \
|
||||
echo "✅ Created .env file"; \
|
||||
fi
|
||||
@mkdir -p logs instance
|
||||
@echo "✅ Created directories"
|
||||
@make deploy
|
||||
@echo ""
|
||||
@echo "=== Installation Complete ==="
|
||||
@echo "Access the application at: http://localhost:8781"
|
||||
@echo "Default login: superadmin / superadmin123"
|
||||
@echo ""
|
||||
@echo "⚠️ Remember to change the default passwords!"
|
||||
88
deploy.sh
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Quick deployment script for Recticel Quality Application
|
||||
|
||||
set -e
|
||||
|
||||
echo "================================================"
|
||||
echo " Recticel Quality Application"
|
||||
echo " Docker Deployment"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Check if Docker is installed
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "❌ Docker is not installed. Please install Docker first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if Docker Compose is installed
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
echo "❌ Docker Compose is not installed. Please install Docker Compose first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Docker and Docker Compose are installed"
|
||||
echo ""
|
||||
|
||||
# Create .env if it doesn't exist
|
||||
if [ ! -f .env ]; then
|
||||
echo "Creating .env file from template..."
|
||||
cp .env.example .env
|
||||
echo "✅ Created .env file"
|
||||
echo "⚠️ Please review .env and update passwords before production use"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Create necessary directories
|
||||
echo "Creating necessary directories..."
|
||||
mkdir -p logs instance
|
||||
echo "✅ Directories created"
|
||||
echo ""
|
||||
|
||||
# Stop any existing services
|
||||
echo "Stopping any existing services..."
|
||||
docker-compose down 2>/dev/null || true
|
||||
echo ""
|
||||
|
||||
# Build and start services
|
||||
echo "Building Docker images..."
|
||||
docker-compose build
|
||||
echo ""
|
||||
|
||||
echo "Starting services..."
|
||||
docker-compose up -d
|
||||
echo ""
|
||||
|
||||
# Wait for services to be ready
|
||||
echo "Waiting for services to be ready..."
|
||||
sleep 10
|
||||
|
||||
# Check status
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Deployment Status"
|
||||
echo "================================================"
|
||||
docker-compose ps
|
||||
echo ""
|
||||
|
||||
# Show access information
|
||||
echo "================================================"
|
||||
echo " ✅ Deployment Complete!"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "Application URL: http://localhost:8781"
|
||||
echo ""
|
||||
echo "Default Login Credentials:"
|
||||
echo " Username: superadmin"
|
||||
echo " Password: superadmin123"
|
||||
echo ""
|
||||
echo "⚠️ IMPORTANT: Change the default password after first login!"
|
||||
echo ""
|
||||
echo "Useful Commands:"
|
||||
echo " View logs: docker-compose logs -f"
|
||||
echo " Stop services: docker-compose down"
|
||||
echo " Restart: docker-compose restart"
|
||||
echo " Shell access: docker-compose exec web bash"
|
||||
echo ""
|
||||
echo "For more information, see DOCKER_DEPLOYMENT.md"
|
||||
echo ""
|
||||
@@ -1,77 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# MariaDB Database Service
|
||||
db:
|
||||
image: mariadb:11.3
|
||||
container_name: recticel-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword}
|
||||
MYSQL_DATABASE: trasabilitate
|
||||
MYSQL_USER: trasabilitate
|
||||
MYSQL_PASSWORD: Initial01!
|
||||
ports:
|
||||
- "${DB_PORT:-3306}:3306"
|
||||
volumes:
|
||||
- /srv/docker-test/mariadb:/var/lib/mysql
|
||||
- ./init-db.sql:/docker-entrypoint-initdb.d/01-init.sql
|
||||
networks:
|
||||
- recticel-network
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
# Flask Web Application Service
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: recticel-app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# Database connection settings
|
||||
DB_HOST: db
|
||||
DB_PORT: 3306
|
||||
DB_NAME: trasabilitate
|
||||
DB_USER: trasabilitate
|
||||
DB_PASSWORD: Initial01!
|
||||
|
||||
# Application settings
|
||||
FLASK_ENV: production
|
||||
FLASK_APP: run.py
|
||||
|
||||
# Initialization flags (set to "false" after first run if needed)
|
||||
INIT_DB: "true"
|
||||
SEED_DB: "true"
|
||||
ports:
|
||||
- "${APP_PORT:-8781}:8781"
|
||||
volumes:
|
||||
# Mount logs directory for persistence
|
||||
- /srv/docker-test/logs:/srv/quality_recticel/logs
|
||||
# Mount instance directory for config persistence
|
||||
- /srv/docker-test/instance:/app/instance
|
||||
# Mount app code for easy updates (DISABLED - causes config issues)
|
||||
# Uncomment only for development, not production
|
||||
# - /srv/docker-test/app:/app
|
||||
networks:
|
||||
- recticel-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8781/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
networks:
|
||||
recticel-network:
|
||||
driver: bridge
|
||||
|
||||
# Note: Using bind mounts to /srv/docker-test/ instead of named volumes
|
||||
# This allows easier access and management of persistent data
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "==================================="
|
||||
echo "Recticel Quality App - Starting"
|
||||
echo "==================================="
|
||||
|
||||
# Wait for MariaDB to be ready
|
||||
echo "Waiting for MariaDB to be ready..."
|
||||
until python3 << END
|
||||
import mariadb
|
||||
import sys
|
||||
import time
|
||||
|
||||
max_retries = 30
|
||||
retry_count = 0
|
||||
|
||||
while retry_count < max_retries:
|
||||
try:
|
||||
conn = mariadb.connect(
|
||||
user="${DB_USER}",
|
||||
password="${DB_PASSWORD}",
|
||||
host="${DB_HOST}",
|
||||
port=int("${DB_PORT}"),
|
||||
database="${DB_NAME}"
|
||||
)
|
||||
conn.close()
|
||||
print("✅ Database connection successful!")
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
retry_count += 1
|
||||
print(f"Database not ready yet (attempt {retry_count}/{max_retries}). Waiting...")
|
||||
time.sleep(2)
|
||||
|
||||
print("❌ Failed to connect to database after 30 attempts")
|
||||
sys.exit(1)
|
||||
END
|
||||
do
|
||||
echo "Retrying database connection..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Create external_server.conf from environment variables
|
||||
echo "Creating database configuration..."
|
||||
cat > /app/instance/external_server.conf << EOF
|
||||
server_domain=${DB_HOST}
|
||||
port=${DB_PORT}
|
||||
database_name=${DB_NAME}
|
||||
username=${DB_USER}
|
||||
password=${DB_PASSWORD}
|
||||
EOF
|
||||
|
||||
echo "✅ Database configuration created"
|
||||
|
||||
# Run database initialization if needed
|
||||
if [ "${INIT_DB}" = "true" ]; then
|
||||
echo "Initializing database schema..."
|
||||
python3 /app/app/db_create_scripts/setup_complete_database.py || echo "⚠️ Database may already be initialized"
|
||||
fi
|
||||
|
||||
# Seed the database with superadmin user
|
||||
if [ "${SEED_DB}" = "true" ]; then
|
||||
echo "Seeding database with superadmin user..."
|
||||
python3 /app/seed.py || echo "⚠️ Database may already be seeded"
|
||||
fi
|
||||
|
||||
echo "==================================="
|
||||
echo "Starting application..."
|
||||
echo "==================================="
|
||||
|
||||
# Execute the CMD
|
||||
exec "$@"
|
||||
20
init-db.sql
@@ -1,20 +0,0 @@
|
||||
-- MariaDB Initialization Script for Recticel Quality Application
|
||||
-- This script creates the database and user if they don't exist
|
||||
|
||||
-- Create database if it doesn't exist
|
||||
CREATE DATABASE IF NOT EXISTS trasabilitate CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- Create user if it doesn't exist (MariaDB 10.2+)
|
||||
CREATE USER IF NOT EXISTS 'trasabilitate'@'%' IDENTIFIED BY 'Initial01!';
|
||||
|
||||
-- Grant all privileges on the database to the user
|
||||
GRANT ALL PRIVILEGES ON trasabilitate.* TO 'trasabilitate'@'%';
|
||||
|
||||
-- Flush privileges to ensure they take effect
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- Select the database
|
||||
USE trasabilitate;
|
||||
|
||||
-- The actual table creation will be handled by the Python setup script
|
||||
-- This ensures compatibility with the existing setup_complete_database.py
|
||||
865
logs/access.log
@@ -1,865 +0,0 @@
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:16 +0300] "GET /print_module HTTP/1.1" 200 69964 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 105688
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:17 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2579
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:17 +0300] "GET /get_unprinted_orders HTTP/1.1" 200 3 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5560
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET /dashboard HTTP/1.1" 302 189 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 15566
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 40767
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 12665
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 14360
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5758
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 26983
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:28 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 30870
|
||||
192.168.0.132 - - [15/Oct/2025:00:30:46 +0300] "POST / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 48983
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:01 +0300] "POST / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7519
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:14 +0300] "POST / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 62448
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:33 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 24735
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:33 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 40939
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:33 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 26109
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:39 +0300] "GET /main_scan HTTP/1.1" 200 1981 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 38217
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:47 +0300] "GET /fg_scan HTTP/1.1" 200 23188 "https://quality.moto-adv.com/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" 34772
|
||||
192.168.0.132 - - [15/Oct/2025:00:31:47 +0300] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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" 2544
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:14 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 17315
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:15 +0300] "GET /dashboard HTTP/1.1" 302 189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2603
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:15 +0300] "GET / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 40000
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:19 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9291
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:19 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9739
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:21 +0300] "GET /quality HTTP/1.1" 200 8292 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10366
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:24 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2422
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:26 +0300] "GET /main_scan HTTP/1.1" 200 1981 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6923
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:27 +0300] "GET /fg_scan HTTP/1.1" 200 23188 "https://quality.moto-adv.com/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" 30751
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:31 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/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" 2426
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:33 +0300] "GET /etichete HTTP/1.1" 200 2420 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 54927
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:35 +0300] "GET /upload_data HTTP/1.1" 200 10558 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21518
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:38 +0300] "GET /etichete HTTP/1.1" 200 2420 "https://quality.moto-adv.com/upload_data" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2995
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:40 +0300] "GET /print_module HTTP/1.1" 200 70135 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 58228
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:40 +0300] "GET /static/qz-tray.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 16021
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:40 +0300] "GET /static/JsBarcode.all.min.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28667
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:40 +0300] "GET /static/html2canvas.min.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 35231
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:40 +0300] "GET /get_pairing_keys HTTP/1.1" 200 118 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3023
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:41 +0300] "GET /get_unprinted_orders HTTP/1.1" 200 3 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 8089
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:45 +0300] "GET /etichete HTTP/1.1" 200 2420 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 40846
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:49 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9861
|
||||
192.168.0.132 - - [15/Oct/2025:01:29:50 +0300] "GET /settings HTTP/1.1" 200 9105 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 29372
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:41 +0300] "HEAD / HTTP/1.1" 200 0 "-" "-" 51821
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:41 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1706
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:42 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 12219
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:42 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5333
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:42 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 13946
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:42 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2079
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:42 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 27067
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:42 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2104
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:43 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10666
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:43 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10094
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:43 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 51915
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:45 +0300] "GET /main_scan HTTP/1.1" 200 1978 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 38423
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:47 +0300] "GET /fg_scan HTTP/1.1" 200 23185 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 32657
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:47 +0300] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2641
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:52 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 8104
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:53 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 2178
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:53 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1912
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:53 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 2623
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:53 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 2380
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:53 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 32438
|
||||
192.168.0.132 - - [15/Oct/2025:15:39:54 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 3180
|
||||
192.168.0.132 - - [15/Oct/2025:15:46:15 +0300] "POST /fg_scan HTTP/1.1" 200 23790 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 41768
|
||||
192.168.0.132 - - [15/Oct/2025:15:46:58 +0300] "POST /fg_scan HTTP/1.1" 200 24394 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 70762
|
||||
192.168.0.132 - - [15/Oct/2025:15:47:44 +0300] "POST /fg_scan HTTP/1.1" 200 24997 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 15544
|
||||
192.168.0.132 - - [15/Oct/2025:15:48:03 +0300] "POST /fg_scan HTTP/1.1" 200 25601 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 41106
|
||||
192.168.0.132 - - [15/Oct/2025:15:48:26 +0300] "POST /fg_scan HTTP/1.1" 200 26205 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 91583
|
||||
192.168.0.132 - - [15/Oct/2025:15:49:21 +0300] "POST /fg_scan HTTP/1.1" 200 26810 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 12878
|
||||
192.168.0.132 - - [15/Oct/2025:15:49:38 +0300] "POST /fg_scan HTTP/1.1" 200 27413 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 76806
|
||||
192.168.0.132 - - [15/Oct/2025:15:49:48 +0300] "POST /fg_scan HTTP/1.1" 200 28017 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14211
|
||||
192.168.0.132 - - [15/Oct/2025:15:49:56 +0300] "POST /fg_scan HTTP/1.1" 200 28621 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13928
|
||||
192.168.0.132 - - [15/Oct/2025:15:50:02 +0300] "POST /fg_scan HTTP/1.1" 200 29225 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13590
|
||||
192.168.0.132 - - [15/Oct/2025:15:50:55 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 10067
|
||||
192.168.0.132 - - [15/Oct/2025:15:50:57 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2988
|
||||
192.168.0.132 - - [15/Oct/2025:15:50:57 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2528
|
||||
192.168.0.132 - - [15/Oct/2025:15:51:06 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 3070
|
||||
192.168.0.132 - - [15/Oct/2025:15:51:06 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9653
|
||||
192.168.0.132 - - [15/Oct/2025:15:51:07 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 3316
|
||||
192.168.0.132 - - [15/Oct/2025:15:51:07 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2520
|
||||
192.168.0.132 - - [15/Oct/2025:15:51:11 +0300] "GET /main_scan HTTP/1.1" 200 1978 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6865
|
||||
192.168.0.132 - - [15/Oct/2025:15:51:16 +0300] "GET /fg_scan HTTP/1.1" 200 29225 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 5743
|
||||
192.168.0.132 - - [15/Oct/2025:15:58:53 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 41424
|
||||
192.168.0.132 - - [15/Oct/2025:15:58:54 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2982
|
||||
192.168.0.132 - - [15/Oct/2025:15:58:54 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9731
|
||||
192.168.0.132 - - [15/Oct/2025:15:58:56 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2857
|
||||
192.168.0.132 - - [15/Oct/2025:15:58:56 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2509
|
||||
192.168.0.132 - - [15/Oct/2025:15:58:57 +0300] "GET /warehouse HTTP/1.1" 200 2421 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8579
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:55 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" 1639
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:56 +0300] "GET /sitemap.xml HTTP/1.1" 404 207 "-" "fasthttp" 1943
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:56 +0300] "GET /sitemap.xml HTTP/1.1" 404 207 "-" "fasthttp" 1420
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:56 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "-" "fasthttp" 1322
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:56 +0300] "GET /robots.txt HTTP/1.1" 404 207 "-" "fasthttp" 1374
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:57 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" 2550
|
||||
192.168.0.132 - - [15/Oct/2025:16:46:57 +0300] "GET /sitemap.xml HTTP/1.1" 404 207 "-" "fasthttp" 1346
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1787
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1981
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2223
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2254
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2182
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2082
|
||||
192.168.0.132 - - [15/Oct/2025:22:42:50 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2049
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:10 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 6531
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:10 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 9664
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:11 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 12203
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:25 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2443
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:25 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2433
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:29 +0300] "GET /quality HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2319
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:29 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2372
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:37 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2324
|
||||
192.168.0.132 - - [15/Oct/2025:22:43:37 +0300] "GET / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2029
|
||||
192.168.0.132 - - [15/Oct/2025:22:44:04 +0300] "POST / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 12509
|
||||
192.168.0.132 - - [15/Oct/2025:22:44:22 +0300] "POST / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 7961
|
||||
192.168.0.132 - - [15/Oct/2025:22:44:45 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 6237
|
||||
192.168.0.132 - - [15/Oct/2025:22:44:45 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2471
|
||||
192.168.0.132 - - [15/Oct/2025:22:44:47 +0300] "GET /quality HTTP/1.1" 200 8292 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 10556
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:00 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2462
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:07 +0300] "GET /settings HTTP/1.1" 200 9105 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 26538
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:11 +0300] "GET /settings HTTP/1.1" 302 207 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 2098
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:11 +0300] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1426
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:11 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1645
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:12 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1632
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:12 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 2022
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:12 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1980
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:12 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 2032
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:12 +0300] "GET / HTTP/1.1" 200 1189 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1610
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:13 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 2004
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:13 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1969
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:13 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1959
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:13 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 (compatible; Google-Read-Aloud; +https://support.google.com/webmasters/answer/1061943)" 1970
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:39 +0300] "POST /delete_user HTTP/1.1" 302 205 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 8755
|
||||
192.168.0.132 - - [15/Oct/2025:22:45:39 +0300] "GET /settings HTTP/1.1" 200 8603 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 26163
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:05 +0300] "POST /create_user HTTP/1.1" 302 205 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 9269
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:05 +0300] "GET /settings HTTP/1.1" 200 9120 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 27376
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:16 +0300] "GET /dashboard HTTP/1.1" 200 2527 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2442
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:17 +0300] "GET /quality HTTP/1.1" 200 8292 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 10378
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:20 +0300] "GET /get_report_data?report=1 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 5109
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:37 +0300] "GET /generate_report?report=6&date=2025-10-15 HTTP/1.1" 200 260 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 6128
|
||||
192.168.0.132 - - [15/Oct/2025:22:46:50 +0300] "GET /get_report_data?report=5 HTTP/1.1" 200 318 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 4085
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:19 +0300] "GET /settings HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1978
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:19 +0300] "GET /dashboard HTTP/1.1" 302 189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2113
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:19 +0300] "GET / HTTP/1.1" 200 1189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1970
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:19 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1712
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:24 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5754
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:24 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9594
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:24 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2385
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:24 +0300] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2150
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:24 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2539
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:24 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2473
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:28 +0300] "GET /main_scan HTTP/1.1" 200 1978 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6850
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:29 +0300] "GET /fg_scan HTTP/1.1" 200 29225 "https://quality.moto-adv.com/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" 5666
|
||||
192.168.0.132 - - [16/Oct/2025:00:04:30 +0300] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/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" 2455
|
||||
192.168.0.132 - - [16/Oct/2025:00:05:32 +0300] "GET /dashboard HTTP/1.1" 200 2524 "https://quality.moto-adv.com/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" 2311
|
||||
192.168.0.132 - - [16/Oct/2025:00:05:34 +0300] "GET /quality HTTP/1.1" 200 8289 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10335
|
||||
192.168.0.132 - - [16/Oct/2025:00:05:36 +0300] "GET /get_report_data?report=1 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 4252
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:42 +0300] "HEAD / HTTP/1.1" 200 0 "-" "-" 59333
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:43 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2227
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:43 +0300] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 12268
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:43 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2160
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:43 +0300] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 27228
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:43 +0300] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 27216
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:43 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 27723
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:44 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2630
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:45 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 11458
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:45 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 47192
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:45 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2496
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:53 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 8221
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:53 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 2406
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:53 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1986
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:53 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1922
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:53 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 2275
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:53 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 6991
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:54 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1579
|
||||
192.168.0.132 - - [16/Oct/2025:08:51:58 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7862
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:00 +0300] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10339
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:04 +0300] "GET /get_report_data?report=1 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4612
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:12 +0300] "GET /generate_report?report=6&date=2025-10-15 HTTP/1.1" 200 260 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 24036
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:17 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 49162
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:24 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8085
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:28 +0300] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21185
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:28 +0300] "GET /static/fg_quality.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2306
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:40 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 62567
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:41 +0300] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7821
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:44 +0300] "GET /fg_scan HTTP/1.1" 200 29680 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 86590
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:44 +0300] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 12851
|
||||
192.168.0.132 - - [16/Oct/2025:08:52:59 +0300] "POST /fg_scan HTTP/1.1" 200 30284 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 39788
|
||||
192.168.0.132 - - [16/Oct/2025:08:53:13 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 62427
|
||||
192.168.0.132 - - [16/Oct/2025:08:53:16 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 48080
|
||||
192.168.0.132 - - [16/Oct/2025:08:53:18 +0300] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10833
|
||||
192.168.0.132 - - [16/Oct/2025:08:53:34 +0300] "GET /get_report_data?report=4 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7108
|
||||
192.168.0.132 - - [16/Oct/2025:08:53:42 +0300] "GET /get_report_data?report=2 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4601
|
||||
192.168.0.132 - - [16/Oct/2025:08:53:52 +0300] "GET /generate_report?report=7&start_date=2025-10-10&end_date=2025-10-16 HTTP/1.1" 200 278 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 15891
|
||||
192.168.0.132 - - [16/Oct/2025:09:00:50 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 62494
|
||||
192.168.0.132 - - [16/Oct/2025:09:00:52 +0300] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6812
|
||||
192.168.0.132 - - [16/Oct/2025:09:00:53 +0300] "GET /fg_scan HTTP/1.1" 200 30284 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 6748
|
||||
192.168.0.132 - - [16/Oct/2025:09:01:38 +0300] "POST /fg_scan HTTP/1.1" 200 30889 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 40541
|
||||
192.168.0.132 - - [16/Oct/2025:09:01:47 +0300] "POST /fg_scan HTTP/1.1" 200 31493 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 12457
|
||||
192.168.0.132 - - [16/Oct/2025:09:01:56 +0300] "POST /fg_scan HTTP/1.1" 200 32097 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13517
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:04 +0300] "POST /fg_scan HTTP/1.1" 200 32702 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 16164
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:12 +0300] "POST /fg_scan HTTP/1.1" 200 32701 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13839
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:18 +0300] "POST /fg_scan HTTP/1.1" 200 32702 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13921
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:27 +0300] "POST /fg_scan HTTP/1.1" 200 32703 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14679
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:33 +0300] "POST /fg_scan HTTP/1.1" 200 32703 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 44686
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:41 +0300] "POST /fg_scan HTTP/1.1" 200 32703 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13734
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:49 +0300] "POST /fg_scan HTTP/1.1" 200 32704 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 47336
|
||||
192.168.0.132 - - [16/Oct/2025:09:02:56 +0300] "POST /fg_scan HTTP/1.1" 200 32706 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14351
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:03 +0300] "POST /fg_scan HTTP/1.1" 200 32707 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 45428
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:09 +0300] "POST /fg_scan HTTP/1.1" 200 32708 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 44776
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:15 +0300] "POST /fg_scan HTTP/1.1" 200 32710 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14234
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:23 +0300] "POST /fg_scan HTTP/1.1" 200 32711 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 78555
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:29 +0300] "POST /fg_scan HTTP/1.1" 200 32727 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14674
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:37 +0300] "POST /fg_scan HTTP/1.1" 200 32728 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14033
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:48 +0300] "POST /fg_scan HTTP/1.1" 200 32729 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 45638
|
||||
192.168.0.132 - - [16/Oct/2025:09:03:56 +0300] "POST /fg_scan HTTP/1.1" 200 32730 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 15193
|
||||
192.168.0.132 - - [16/Oct/2025:09:04:02 +0300] "POST /fg_scan HTTP/1.1" 200 32731 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13520
|
||||
192.168.0.132 - - [16/Oct/2025:09:04:09 +0300] "POST /fg_scan HTTP/1.1" 200 32731 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14452
|
||||
192.168.0.132 - - [16/Oct/2025:09:04:16 +0300] "POST /fg_scan HTTP/1.1" 200 32747 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13658
|
||||
192.168.0.132 - - [16/Oct/2025:09:04:23 +0300] "POST /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 15046
|
||||
192.168.0.132 - - [16/Oct/2025:09:04:30 +0300] "POST /fg_scan HTTP/1.1" 200 32749 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 14806
|
||||
192.168.0.132 - - [16/Oct/2025:09:04:39 +0300] "POST /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 15571
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:05 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2680
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:07 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8030
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:09 +0300] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10612
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:18 +0300] "GET /get_report_data?report=1 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4695
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:32 +0300] "GET /generate_report?report=6&date=2025-10-16 HTTP/1.1" 200 260 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6501
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:42 +0300] "GET /generate_report?report=6&date=2025-10-15 HTTP/1.1" 200 260 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6382
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:50 +0300] "GET /generate_report?report=7&start_date=2025-10-15&end_date=2025-10-16 HTTP/1.1" 200 278 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 14148
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:56 +0300] "GET /get_report_data?report=3 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4641
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:58 +0300] "GET /get_report_data?report=3 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4582
|
||||
192.168.0.132 - - [16/Oct/2025:09:11:59 +0300] "GET /get_report_data?report=3 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4522
|
||||
192.168.0.132 - - [16/Oct/2025:09:12:05 +0300] "GET /generate_report?report=8&date=2025-10-16 HTTP/1.1" 200 283 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6487
|
||||
192.168.0.132 - - [16/Oct/2025:11:00:59 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 8136
|
||||
192.168.0.132 - - [16/Oct/2025:11:00:59 +0300] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2333
|
||||
192.168.0.132 - - [16/Oct/2025:11:00:59 +0300] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 11439
|
||||
192.168.0.132 - - [16/Oct/2025:11:00:59 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1919
|
||||
192.168.0.132 - - [16/Oct/2025:11:00:59 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1830
|
||||
192.168.0.132 - - [16/Oct/2025:11:00:59 +0300] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1831
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8149
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2140
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1975
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1852
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 12593
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4655
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:19 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1982
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:22 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 12596
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:36 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6126
|
||||
192.168.0.132 - - [16/Oct/2025:13:33:53 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6013
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:08 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5729
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:08 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9454
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:08 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21784
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:11 +0300] "GET /etichete HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2607
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:11 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2399
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:17 +0300] "GET /etichete HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2524
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:17 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2449
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:19 +0300] "GET /warehouse HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2532
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:19 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2454
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:20 +0300] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6946
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:24 +0300] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 6140
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:25 +0300] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 12829
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:31 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2378
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:35 +0300] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21547
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:35 +0300] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2529
|
||||
192.168.0.132 - - [16/Oct/2025:13:34:48 +0300] "GET /generate_fg_report?report=6&date=2025-10-15 HTTP/1.1" 200 1005 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 14935
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:05 +0300] "GET /generate_fg_report?report=7&start_date=2025-10-01&end_date=2025-10-16 HTTP/1.1" 200 299 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5653
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:10 +0300] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 3262 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7121
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:20 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2455
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:23 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2794
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:23 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8466
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:42 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5707
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:43 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9588
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:46 +0300] "GET /etichete HTTP/1.1" 200 2872 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8919
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:49 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2510
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:50 +0300] "GET /warehouse HTTP/1.1" 200 2876 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8327
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:54 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/warehouse" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2740
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:54 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/warehouse" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 8441
|
||||
192.168.0.132 - - [16/Oct/2025:13:35:59 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6225
|
||||
192.168.0.132 - - [16/Oct/2025:13:36:21 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6115
|
||||
192.168.0.132 - - [16/Oct/2025:13:36:32 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6034
|
||||
192.168.0.132 - - [16/Oct/2025:13:36:51 +0300] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6110
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:47 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1690
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:47 +0300] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2181
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:47 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1802
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:47 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1999
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:47 +0300] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1929
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:47 +0300] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2006
|
||||
192.168.0.132 - - [16/Oct/2025:13:51:48 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1467
|
||||
192.168.0.132 - - [16/Oct/2025:13:52:04 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5385
|
||||
192.168.0.132 - - [16/Oct/2025:13:52:04 +0300] "GET /dashboard HTTP/1.1" 200 2935 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2389
|
||||
192.168.0.132 - - [16/Oct/2025:13:52:04 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2263
|
||||
192.168.0.132 - - [16/Oct/2025:13:52:17 +0300] "GET /settings HTTP/1.1" 200 10008 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 29183
|
||||
192.168.0.132 - - [16/Oct/2025:13:52:22 +0300] "GET /user_management_simple HTTP/1.1" 200 40501 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 53904
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:17 +0300] "POST /create_user_simple HTTP/1.1" 302 233 "https://quality.moto-adv.com/user_management_simple" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7772
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:17 +0300] "GET /user_management_simple HTTP/1.1" 200 43469 "https://quality.moto-adv.com/user_management_simple" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 53063
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:21 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/user_management_simple" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2427
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:21 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/user_management_simple" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2058
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:39 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5679
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:39 +0300] "GET /dashboard HTTP/1.1" 200 2933 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9512
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:45 +0300] "GET /main_scan HTTP/1.1" 200 2434 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6796
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:46 +0300] "GET /fg_scan HTTP/1.1" 200 32749 "https://quality.moto-adv.com/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" 6066
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:47 +0300] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/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" 2323
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:49 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/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" 2310
|
||||
192.168.0.132 - - [16/Oct/2025:13:53:49 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/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" 2088
|
||||
192.168.0.132 - - [16/Oct/2025:16:38:47 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2044
|
||||
192.168.0.132 - - [16/Oct/2025:16:38:49 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5727
|
||||
192.168.0.132 - - [16/Oct/2025:16:38:49 +0300] "GET /dashboard HTTP/1.1" 200 2933 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2374
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:01 +0300] "GET /main_scan HTTP/1.1" 200 2434 "https://quality.moto-adv.com/dashboard" "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.132 - - [16/Oct/2025:16:39:05 +0300] "GET /fg_scan HTTP/1.1" 200 32749 "https://quality.moto-adv.com/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" 6086
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:14 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/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" 2310
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:14 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/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" 2055
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:32 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5846
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:32 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9387
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:40 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2287
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:42 +0300] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21146
|
||||
192.168.0.132 - - [16/Oct/2025:16:39:42 +0300] "GET /static/fg_quality.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_quality" "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.132 - - [16/Oct/2025:16:39:45 +0300] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 3262 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6944
|
||||
192.168.0.132 - - [16/Oct/2025:16:40:01 +0300] "GET /get_fg_report_data?report=1 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6236
|
||||
192.168.0.132 - - [16/Oct/2025:16:40:11 +0300] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 3262 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7015
|
||||
192.168.0.132 - - [16/Oct/2025:16:40:24 +0300] "GET /get_fg_report_data?report=1 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6368
|
||||
192.168.0.132 - - [16/Oct/2025:16:40:49 +0300] "GET /get_fg_report_data?report=4 HTTP/1.1" 200 1611 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5934
|
||||
192.168.0.132 - - [16/Oct/2025:21:15:08 +0300] "GET /main_scan HTTP/1.1" 302 189 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2141
|
||||
192.168.0.132 - - [16/Oct/2025:21:15:08 +0300] "GET /print_module HTTP/1.1" 200 70419 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 54374
|
||||
192.168.0.132 - - [16/Oct/2025:21:15:08 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1995
|
||||
192.168.0.132 - - [16/Oct/2025:21:15:09 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1783
|
||||
192.168.0.132 - - [16/Oct/2025:21:15:09 +0300] "GET /get_unprinted_orders HTTP/1.1" 200 3 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5239
|
||||
192.168.0.132 - - [17/Oct/2025:02:39:07 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1670
|
||||
192.168.0.132 - - [17/Oct/2025:02:39:11 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1959
|
||||
192.168.0.132 - - [17/Oct/2025:02:39:46 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1418
|
||||
192.168.0.132 - - [17/Oct/2025:03:56:17 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0" 1711
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:25 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1428
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:37 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5639
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:37 +0300] "GET /dashboard HTTP/1.1" 200 2935 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2322
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:37 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2445
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:37 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 12977
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:37 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2398
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:37 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 27154
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:42 +0300] "GET /settings HTTP/1.1" 200 10517 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28159
|
||||
192.168.0.132 - - [17/Oct/2025:20:46:51 +0300] "GET /user_management_simple HTTP/1.1" 200 43469 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 54418
|
||||
192.168.0.132 - - [18/Oct/2025:14:01:44 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2011
|
||||
192.168.0.132 - - [18/Oct/2025:14:25:59 +0300] "GET / HTTP/1.1" 200 1627 "-" "-" 1667
|
||||
192.168.0.132 - - [18/Oct/2025:14:44:53 +0300] "GET /.env HTTP/1.1" 404 207 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0" 1440
|
||||
192.168.0.132 - - [18/Oct/2025:14:44:54 +0300] "POST / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0" 2620
|
||||
192.168.0.132 - - [18/Oct/2025:16:52:25 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 8041
|
||||
192.168.0.132 - - [19/Oct/2025:02:26:25 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 zgrab/0.x" 1656
|
||||
192.168.0.132 - - [19/Oct/2025:02:26:28 +0300] "GET / HTTP/1.1" 200 1627 "http://quality.moto-adv.com/" "Mozilla/5.0 zgrab/0.x" 1671
|
||||
192.168.0.132 - - [19/Oct/2025:03:06:04 +0300] "GET / HTTP/1.1" 200 1627 "http://quality.moto-adv.com/" "Mozilla/5.0 zgrab/0.x" 8039
|
||||
192.168.0.132 - - [19/Oct/2025:03:06:10 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 zgrab/0.x" 1639
|
||||
192.168.0.132 - - [19/Oct/2025:05:41:14 +0300] "GET /robots.txt HTTP/1.1" 404 207 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.0; +https://openai.com/gptbot)" 1928
|
||||
192.168.0.132 - - [20/Oct/2025:00:49:20 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1627
|
||||
192.168.0.132 - - [20/Oct/2025:00:49:28 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1371
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2168
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1986
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2691
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2467
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2174
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2198
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4845
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:33 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1730
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:35 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5838
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:35 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2350
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:35 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 18882
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:41 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7780
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:43 +0300] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10372
|
||||
192.168.0.132 - - [20/Oct/2025:10:28:51 +0300] "GET /get_report_data?report=2 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4299
|
||||
192.168.0.132 - - [20/Oct/2025:10:29:00 +0300] "GET /generate_report?report=8&date=2025-10-16 HTTP/1.1" 200 283 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6147
|
||||
192.168.0.132 - - [20/Oct/2025:10:29:13 +0300] "GET /get_report_data?report=5 HTTP/1.1" 200 318 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 3976
|
||||
192.168.0.132 - - [20/Oct/2025:10:30:49 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7789
|
||||
192.168.0.132 - - [20/Oct/2025:10:30:55 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2344
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:00 +0300] "GET /settings HTTP/1.1" 302 207 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2319
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:00 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2371
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:04 +0300] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6895
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:07 +0300] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 6094
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:07 +0300] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2419
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:33 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2359
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:42 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2335
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:49 +0300] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2458
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:49 +0300] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2509
|
||||
192.168.0.132 - - [20/Oct/2025:10:31:53 +0300] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6278
|
||||
192.168.0.132 - - [20/Oct/2025:10:32:19 +0300] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6303
|
||||
192.168.0.132 - - [20/Oct/2025:10:32:26 +0300] "GET /generate_fg_report?report=7&start_date=2025-10-15&end_date=2025-10-20 HTTP/1.1" 200 299 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 14413
|
||||
192.168.0.132 - - [20/Oct/2025:10:33:00 +0300] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 3262 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7108
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:36 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1710
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:36 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2041
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:36 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2084
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:36 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 4555
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:37 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1872
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:37 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1883
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:37 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1410
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:42 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5474
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:42 +0300] "GET /dashboard HTTP/1.1" 200 2935 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2416
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:42 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21312
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:47 +0300] "GET /reports HTTP/1.1" 200 3280 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7823
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:49 +0300] "GET /fg_quality HTTP/1.1" 200 22449 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2366
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:49 +0300] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2388
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:52 +0300] "GET /get_fg_report_data?report=1 HTTP/1.1" 200 166 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 4316
|
||||
192.168.0.132 - - [20/Oct/2025:11:40:56 +0300] "GET /generate_fg_report?report=6&date=2025-10-16 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6882
|
||||
192.168.0.132 - - [20/Oct/2025:11:42:47 +0300] "GET /get_fg_report_data?report=1 HTTP/1.1" 200 166 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 4306
|
||||
192.168.0.132 - - [20/Oct/2025:11:42:55 +0300] "GET /generate_fg_report?report=6&date=2025-10-16 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 15831
|
||||
192.168.0.132 - - [20/Oct/2025:11:43:02 +0300] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6448
|
||||
192.168.0.132 - - [20/Oct/2025:11:43:18 +0300] "GET /generate_fg_report?report=7&date=2025-10-16 HTTP/1.1" 200 103 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3378
|
||||
192.168.0.132 - - [20/Oct/2025:11:43:25 +0300] "GET /test_fg_database HTTP/1.1" 200 1546 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7625
|
||||
192.168.0.132 - - [20/Oct/2025:11:43:28 +0300] "GET /logout HTTP/1.1" 302 189 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2213
|
||||
192.168.0.132 - - [20/Oct/2025:11:43:28 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1986
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET /fg_quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1944
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1999
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2319
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2110
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2149
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2058
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:02 +0300] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2163
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:03 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1751
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:11 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5765
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:11 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "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.132 - - [20/Oct/2025:13:09:11 +0300] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2294
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:29 +0300] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2407
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:36 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2285
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:39 +0300] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 20956
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:39 +0300] "GET /static/fg_quality.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2523
|
||||
192.168.0.132 - - [20/Oct/2025:13:09:58 +0300] "GET /generate_fg_report?report=7&start_date=2025-10-14&end_date=2025-10-20 HTTP/1.1" 200 299 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 14570
|
||||
192.168.0.132 - - [20/Oct/2025:13:10:05 +0300] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7771
|
||||
192.168.0.132 - - [20/Oct/2025:13:10:07 +0300] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "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.132 - - [20/Oct/2025:13:10:14 +0300] "GET /generate_fg_report?report=7&start_date=2025-10-15&end_date=2025-10-20 HTTP/1.1" 200 299 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 5450
|
||||
192.168.0.132 - - [20/Oct/2025:13:10:19 +0300] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6302
|
||||
192.168.0.132 - - [20/Oct/2025:15:06:43 +0300] "GET / HTTP/1.1" 200 1627 "http://172.67.151.21:80/" "-" 1675
|
||||
192.168.0.132 - - [21/Oct/2025:05:11:27 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0" 1728
|
||||
192.168.0.132 - - [22/Oct/2025:03:53:30 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0" 1650
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:19 +0300] "GET / HTTP/1.1" 200 1627 "http://quality.moto-adv.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 1665
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:19 +0300] "GET /app/ HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 1970
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:19 +0300] "GET /login/ HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 1510
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:20 +0300] "GET /static/style.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 2398
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:20 +0300] "GET /static/script.js HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 2044
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:21 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 2019
|
||||
192.168.0.132 - - [22/Oct/2025:10:47:22 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" 2009
|
||||
192.168.0.132 - - [22/Oct/2025:11:22:49 +0300] "GET /user_management_simple HTTP/1.1" 302 189 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1925
|
||||
192.168.0.132 - - [22/Oct/2025:11:22:49 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2032
|
||||
192.168.0.132 - - [22/Oct/2025:11:22:50 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1773
|
||||
192.168.0.132 - - [22/Oct/2025:18:45:12 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1959
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:31 +0300] "GET / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 59557
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:32 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 13236
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:32 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 27376
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:32 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28792
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:32 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 27400
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:32 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 35000
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:39 +0300] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 12245
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:39 +0300] "GET /dashboard HTTP/1.1" 200 2935 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 47232
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:39 +0300] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 26952
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:44 +0300] "GET /reports HTTP/1.1" 200 3280 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 8066
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:46 +0300] "GET /fg_quality HTTP/1.1" 200 22449 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21126
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:46 +0300] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2489
|
||||
192.168.0.132 - - [22/Oct/2025:21:02:59 +0300] "GET /generate_fg_report?report=6&date=2025-10-16 HTTP/1.1" 200 2422 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 35769
|
||||
192.168.0.132 - - [22/Oct/2025:21:03:18 +0300] "GET /quality HTTP/1.1" 200 8860 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10411
|
||||
192.168.0.132 - - [23/Oct/2025:00:18:40 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" 59084
|
||||
192.168.0.132 - - [23/Oct/2025:00:18:41 +0300] "POST / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" 5974
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /.well-known/change-password HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 3174
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200 HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1381
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 8205
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2287
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2370
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2078
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 4452
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:55 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1950
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:56 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1364
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:58 +0300] "GET / HTTP/1.1" 200 1627 "https://www.google.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.52 Mobile Safari/537.36" 45825
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:59 +0300] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.52 Mobile Safari/537.36" 2111
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:59 +0300] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.52 Mobile Safari/537.36" 2136
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:59 +0300] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.52 Mobile Safari/537.36" 4653
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:59 +0300] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.52 Mobile Safari/537.36" 1971
|
||||
192.168.0.132 - - [24/Oct/2025:19:45:59 +0300] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.7339.52 Mobile Safari/537.36" 3201
|
||||
192.168.0.132 - - [25/Oct/2025:03:24:51 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 zgrab/0.x" 44791
|
||||
192.168.0.132 - - [25/Oct/2025:03:24:56 +0300] "GET / HTTP/1.1" 200 1627 "http://quality.moto-adv.com/" "Mozilla/5.0 zgrab/0.x" 59615
|
||||
192.168.0.132 - - [25/Oct/2025:05:02:20 +0300] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" 59482
|
||||
192.168.0.132 - - [25/Oct/2025:05:02:21 +0300] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" 2612
|
||||
192.168.0.132 - - [25/Oct/2025:11:57:37 +0300] "GET / HTTP/1.1" 200 1627 "-" "-" 46568
|
||||
192.168.0.132 - - [25/Oct/2025:12:15:43 +0300] "GET / HTTP/1.1" 200 1627 "-" "-" 47085
|
||||
192.168.0.132 - - [26/Oct/2025:09:28:48 +0200] "GET /robots.txt HTTP/1.1" 404 207 "http://quality.moto-adv.com/robots.txt" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36; compatible; OAI-SearchBot/1.0; robots.txt; +https://openai.com/searchbot" 2129
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:56 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1703
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:56 +0200] "GET //wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1929
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:56 +0200] "GET //xmlrpc.php?rsd HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1466
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:57 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1741
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:57 +0200] "GET //blog/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1441
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:57 +0200] "GET //web/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1362
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:57 +0200] "GET //wordpress/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1372
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:57 +0200] "GET //website/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 2574
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:58 +0200] "GET //wp/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 2042
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:58 +0200] "GET //news/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1445
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:58 +0200] "GET //2018/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1362
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:58 +0200] "GET //2019/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1347
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:58 +0200] "GET //shop/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1358
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:59 +0200] "GET //wp1/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1448
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:59 +0200] "GET //test/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1419
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:59 +0200] "GET //media/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1365
|
||||
192.168.0.132 - - [26/Oct/2025:15:05:59 +0200] "GET //wp2/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1365
|
||||
192.168.0.132 - - [26/Oct/2025:15:06:00 +0200] "GET //site/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1385
|
||||
192.168.0.132 - - [26/Oct/2025:15:06:00 +0200] "GET //cms/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1375
|
||||
192.168.0.132 - - [26/Oct/2025:15:06:00 +0200] "GET //sito/wp-includes/wlwmanifest.xml HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" 1433
|
||||
192.168.0.132 - - [26/Oct/2025:17:11:18 +0200] "GET / HTTP/1.1" 200 1627 "http://172.67.151.21:80/" "-" 1691
|
||||
192.168.0.132 - - [27/Oct/2025:18:03:15 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36" 1790
|
||||
192.168.0.132 - - [27/Oct/2025:18:03:16 +0200] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36" 2274
|
||||
192.168.0.132 - - [27/Oct/2025:18:03:16 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36" 1909
|
||||
192.168.0.132 - - [27/Oct/2025:18:03:16 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36" 1863
|
||||
192.168.0.132 - - [27/Oct/2025:18:03:16 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36" 13453
|
||||
192.168.0.132 - - [27/Oct/2025:18:03:16 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36" 5716
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:02 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1736
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:03 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2059
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:03 +0200] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1954
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:03 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1932
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:03 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 12851
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:03 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6034
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:03 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 1485
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:21 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10781
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:22 +0200] "GET /dashboard HTTP/1.1" 200 2935 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10197
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:22 +0200] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21028
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:26 +0200] "GET /etichete HTTP/1.1" 200 2875 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9086
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:32 +0200] "GET /upload_data HTTP/1.1" 200 11013 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 23622
|
||||
192.168.0.132 - - [27/Oct/2025:18:25:57 +0200] "POST /upload_data HTTP/1.1" 200 20988 "https://quality.moto-adv.com/upload_data" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28498
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:00 +0200] "POST /upload_data HTTP/1.1" 302 211 "https://quality.moto-adv.com/upload_data" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 28625
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:00 +0200] "GET /upload_data HTTP/1.1" 200 11013 "https://quality.moto-adv.com/upload_data" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2460
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:02 +0200] "GET /etichete HTTP/1.1" 200 2875 "https://quality.moto-adv.com/upload_data" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9547
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:04 +0200] "GET /print_module HTTP/1.1" 200 70590 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 59404
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:04 +0200] "GET /static/JsBarcode.all.min.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2704
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:04 +0200] "GET /static/html2canvas.min.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 3308
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:04 +0200] "GET /static/qz-tray.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 7102
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:04 +0200] "GET /get_pairing_keys HTTP/1.1" 200 118 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2104
|
||||
192.168.0.132 - - [27/Oct/2025:18:26:04 +0200] "GET /get_unprinted_orders HTTP/1.1" 200 6116 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9341
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:05 +0200] "POST /generate_label_pdf HTTP/1.1" 200 2878 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 33772
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:16 +0200] "GET /print_module HTTP/1.1" 200 70590 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 55648
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:16 +0200] "GET /get_pairing_keys HTTP/1.1" 200 118 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2047
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:16 +0200] "GET /get_unprinted_orders HTTP/1.1" 200 6116 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6824
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:22 +0200] "POST /generate_label_pdf HTTP/1.1" 200 2868 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21762
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:31 +0200] "POST /generate_label_pdf HTTP/1.1" 200 2869 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 21527
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:32 +0200] "POST /generate_label_pdf HTTP/1.1" 200 2866 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 10506
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:32 +0200] "POST /update_printed_status/1 HTTP/1.1" 200 55 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 9398
|
||||
192.168.0.132 - - [27/Oct/2025:18:30:32 +0200] "GET /get_unprinted_orders HTTP/1.1" 200 5656 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 6564
|
||||
192.168.0.132 - - [27/Oct/2025:18:31:13 +0200] "GET /etichete HTTP/1.1" 200 2875 "https://quality.moto-adv.com/print_module" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 2410
|
||||
192.168.0.132 - - [27/Oct/2025:18:31:15 +0200] "GET /view_orders HTTP/1.1" 200 29615 "https://quality.moto-adv.com/etichete" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" 39480
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2065
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2061
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2582
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2151
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2487
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4008
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4021
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:43 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1770
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:45 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9271
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:45 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9579
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:45 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2381
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:49 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6870
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:51 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 31817
|
||||
192.168.0.132 - - [28/Oct/2025:14:15:51 +0200] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2538
|
||||
192.168.0.132 - - [28/Oct/2025:15:53:58 +0200] "GET / HTTP/1.1" 200 1627 "-" "Hello from Palo Alto Networks, find out more about our scans in https://docs-cortex.paloaltonetworks.com/r/1/Cortex-Xpanse/Scanning-activity" 1619
|
||||
192.168.0.132 - - [28/Oct/2025:17:01:18 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3" 1715
|
||||
192.168.0.132 - - [29/Oct/2025:07:12:07 +0200] "GET /robots.txt HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36; compatible; OAI-SearchBot/1.0; robots.txt; +https://openai.com/searchbot" 2021
|
||||
192.168.0.132 - - [29/Oct/2025:16:20:43 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1702
|
||||
192.168.0.132 - - [29/Oct/2025:16:20:48 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1422
|
||||
192.168.0.132 - - [29/Oct/2025:16:21:17 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" 1369
|
||||
192.168.0.132 - - [29/Oct/2025:18:19:58 +0200] "GET /.env HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3" 1349
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2100
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2050
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2411
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2414
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2227
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5545
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 14721
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:52 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1794
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:54 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5932
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:54 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2363
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:54 +0200] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21798
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:55 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7532
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:57 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 34721
|
||||
192.168.0.132 - - [30/Oct/2025:09:04:57 +0200] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2743
|
||||
192.168.0.132 - - [01/Nov/2025:06:07:25 +0200] "GET /robots.txt HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36; compatible; OAI-SearchBot/1.0; robots.txt; +https://openai.com/searchbot" 1345
|
||||
192.168.0.132 - - [01/Nov/2025:06:07:28 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 1677
|
||||
192.168.0.132 - - [01/Nov/2025:06:07:40 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 1980
|
||||
192.168.0.132 - - [01/Nov/2025:06:07:43 +0200] "GET /static/style.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 1990
|
||||
192.168.0.132 - - [01/Nov/2025:06:07:48 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 2033
|
||||
192.168.0.132 - - [01/Nov/2025:06:07:51 +0200] "GET /static/script.js HTTP/1.1" 200 0 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 2053
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2202
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2008
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2576
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 13304
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2213
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2422
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5104
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:16 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1873
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:19 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6530
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:19 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9786
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:20 +0200] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 24773
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:21 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7345
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:23 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 31921
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:23 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2543
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:31 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2392
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:34 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7968
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:36 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21476
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:36 +0200] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2460
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:39 +0200] "GET /get_fg_report_data?report=2 HTTP/1.1" 200 166 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4690
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:40 +0200] "GET /get_fg_report_data?report=3 HTTP/1.1" 200 151 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4449
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:44 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7745
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:45 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10280
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:51 +0200] "GET /generate_report?report=8&date=2025-11-11 HTTP/1.1" 200 283 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6276
|
||||
192.168.0.132 - - [01/Nov/2025:10:33:53 +0200] "GET /get_report_data?report=2 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4671
|
||||
192.168.0.132 - - [01/Nov/2025:10:34:20 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7889
|
||||
192.168.0.132 - - [01/Nov/2025:10:34:23 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2472
|
||||
192.168.0.132 - - [01/Nov/2025:10:35:00 +0200] "GET /generate_fg_report?report=7&start_date=2025-10-01&end_date=2025-11-01 HTTP/1.1" 200 299 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 14525
|
||||
192.168.0.132 - - [01/Nov/2025:10:35:11 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7873
|
||||
192.168.0.132 - - [01/Nov/2025:10:35:15 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21160
|
||||
192.168.0.132 - - [01/Nov/2025:10:35:28 +0200] "GET /generate_fg_report?report=7&start_date=2025-10-01&end_date=2025-11-01 HTTP/1.1" 200 299 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 14785
|
||||
192.168.0.132 - - [01/Nov/2025:10:35:55 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2371
|
||||
192.168.0.132 - - [01/Nov/2025:10:35:58 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 20827
|
||||
192.168.0.132 - - [01/Nov/2025:10:36:33 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 3262 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 7146
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:23 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2320
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:25 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2418
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:29 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2330
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:31 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10460
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:34 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2304
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:44 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10361
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:49 +0200] "GET /get_report_data?report=5 HTTP/1.1" 200 318 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4134
|
||||
192.168.0.132 - - [01/Nov/2025:13:35:59 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9470
|
||||
192.168.0.132 - - [01/Nov/2025:13:36:06 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6724
|
||||
192.168.0.132 - - [01/Nov/2025:13:36:09 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 5998
|
||||
192.168.0.132 - - [01/Nov/2025:13:36:16 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2421
|
||||
192.168.0.132 - - [01/Nov/2025:13:36:18 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2360
|
||||
192.168.0.132 - - [01/Nov/2025:13:36:20 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 21253
|
||||
192.168.0.132 - - [01/Nov/2025:13:36:22 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 3262 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 10021
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:24 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1672
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:24 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2112
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:24 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1886
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:24 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1765
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:24 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1812
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:24 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1964
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:25 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1422
|
||||
192.168.0.132 - - [01/Nov/2025:14:12:50 +0200] "POST / HTTP/1.1" 200 1627 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5885
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:07 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5636
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:07 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2370
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:07 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2492
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:18 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9524
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:21 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2442
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:28 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2317
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:33 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 6020
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:33 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2520
|
||||
192.168.0.132 - - [01/Nov/2025:14:13:59 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2348
|
||||
192.168.0.132 - - [01/Nov/2025:14:14:00 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2266
|
||||
192.168.0.132 - - [01/Nov/2025:14:14:02 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2341
|
||||
192.168.0.132 - - [01/Nov/2025:14:14:07 +0200] "GET /get_report_data?report=1 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4387
|
||||
192.168.0.132 - - [01/Nov/2025:14:14:11 +0200] "GET /get_report_data?report=2 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4331
|
||||
192.168.0.132 - - [01/Nov/2025:14:14:13 +0200] "GET /get_report_data?report=3 HTTP/1.1" 200 151 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 4278
|
||||
192.168.0.132 - - [01/Nov/2025:14:18:45 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2340
|
||||
192.168.0.132 - - [01/Nov/2025:14:18:51 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2240
|
||||
192.168.0.132 - - [01/Nov/2025:14:18:53 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 5947
|
||||
192.168.0.132 - - [01/Nov/2025:15:05:28 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2426
|
||||
192.168.0.132 - - [01/Nov/2025:15:05:49 +0200] "GET /dashboard HTTP/1.1" 200 2932 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9552
|
||||
192.168.0.132 - - [01/Nov/2025:15:05:54 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2302
|
||||
192.168.0.132 - - [01/Nov/2025:15:05:57 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 6279
|
||||
192.168.0.132 - - [01/Nov/2025:15:06:03 +0200] "GET /dashboard HTTP/1.1" 200 2932 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2373
|
||||
192.168.0.132 - - [01/Nov/2025:15:24:11 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1654
|
||||
192.168.0.132 - - [01/Nov/2025:15:24:11 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1678
|
||||
192.168.0.132 - - [01/Nov/2025:15:24:22 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6942
|
||||
192.168.0.132 - - [01/Nov/2025:15:24:22 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2365
|
||||
192.168.0.132 - - [03/Nov/2025:07:11:21 +0200] "GET /robots.txt HTTP/1.1" 404 207 "http://quality.moto-adv.com/robots.txt" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36; compatible; OAI-SearchBot/1.0; robots.txt; +https://openai.com/searchbot" 1356
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:58 +0200] "HEAD / HTTP/1.1" 200 0 "-" "-" 1580
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1651
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2055
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1888
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 3648
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 3133
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2265
|
||||
192.168.0.132 - - [03/Nov/2025:10:31:59 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1368
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:09 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1708
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:09 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 2150
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:09 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1980
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:09 +0200] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1895
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:09 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 6018
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:09 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1854
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:10 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36" 1417
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:37 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5597
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:37 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2315
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:37 +0200] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 28232
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:41 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6834
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:45 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 31993
|
||||
192.168.0.132 - - [03/Nov/2025:10:32:45 +0200] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2377
|
||||
192.168.0.132 - - [03/Nov/2025:11:48:37 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 2346
|
||||
192.168.0.132 - - [03/Nov/2025:11:49:12 +0200] "GET /dashboard HTTP/1.1" 200 2932 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 9463
|
||||
192.168.0.132 - - [03/Nov/2025:11:49:42 +0200] "GET /dashboard HTTP/1.1" 200 2932 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2339
|
||||
192.168.0.132 - - [03/Nov/2025:11:49:46 +0200] "GET /dashboard HTTP/1.1" 200 2932 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2363
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:07 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1412
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:07 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1705
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:11 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 6069
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:11 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2302
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:20 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1488
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:20 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1673
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:28 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1422
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:28 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 1683
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:29 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 5238
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:29 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2331
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:35 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" 2190
|
||||
192.168.0.132 - - [03/Nov/2025:11:50:40 +0200] "GET /fg_scan HTTP/1.1" 200 32748 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 5936
|
||||
192.168.0.132 - - [03/Nov/2025:11:55:23 +0200] "POST /fg_scan HTTP/1.1" 200 32746 "https://quality.moto-adv.com/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 Edg/141.0.0.0" 13926
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:11 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1600
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:11 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1720
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:14 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6972
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:15 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2323
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:19 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6757
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:21 +0200] "GET /fg_scan HTTP/1.1" 200 32746 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 31759
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:26 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1424
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:26 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1666
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:28 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5215
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:29 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2343
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:31 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6803
|
||||
192.168.0.132 - - [03/Nov/2025:12:03:33 +0200] "GET /fg_scan HTTP/1.1" 200 32746 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 31209
|
||||
192.168.0.132 - - [03/Nov/2025:12:04:39 +0200] "POST /fg_scan HTTP/1.1" 200 32743 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13797
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:35 +0200] "GET /dashboard HTTP/1.1" 200 2932 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2397
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:40 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1491
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:41 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1664
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:42 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7330
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:42 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2354
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:43 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2209
|
||||
192.168.0.132 - - [03/Nov/2025:12:58:44 +0200] "GET /fg_scan HTTP/1.1" 200 32743 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5933
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1931
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2084
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2312
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2067
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2235
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3114
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:19 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2149
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:20 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1678
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:21 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5683
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:21 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2395
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:21 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2433
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:24 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7785
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:26 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2471
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:26 +0200] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2420
|
||||
192.168.0.132 - - [03/Nov/2025:13:18:49 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 3431 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7001
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:30 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2309
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:32 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2325
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:35 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2339
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:38 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2384
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:39 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2294
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:44 +0200] "GET /fg_scan HTTP/1.1" 200 32743 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6050
|
||||
192.168.0.132 - - [03/Nov/2025:13:50:44 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2300
|
||||
192.168.0.132 - - [03/Nov/2025:13:52:27 +0200] "POST /fg_scan HTTP/1.1" 200 32740 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 40117
|
||||
192.168.0.132 - - [03/Nov/2025:15:46:04 +0200] "POST /fg_scan HTTP/1.1" 200 32736 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12290
|
||||
192.168.0.132 - - [03/Nov/2025:15:46:44 +0200] "POST /fg_scan HTTP/1.1" 200 32733 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14099
|
||||
192.168.0.132 - - [03/Nov/2025:15:47:38 +0200] "POST /fg_scan HTTP/1.1" 200 32729 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13936
|
||||
192.168.0.132 - - [03/Nov/2025:15:48:02 +0200] "POST /fg_scan HTTP/1.1" 200 32726 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14869
|
||||
192.168.0.132 - - [03/Nov/2025:15:48:20 +0200] "POST /fg_scan HTTP/1.1" 200 32723 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13530
|
||||
192.168.0.132 - - [03/Nov/2025:15:48:46 +0200] "POST /fg_scan HTTP/1.1" 200 32719 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14615
|
||||
192.168.0.132 - - [03/Nov/2025:15:49:07 +0200] "POST /fg_scan HTTP/1.1" 200 32716 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13523
|
||||
192.168.0.132 - - [03/Nov/2025:15:49:35 +0200] "POST /fg_scan HTTP/1.1" 200 32713 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14801
|
||||
192.168.0.132 - - [03/Nov/2025:15:49:51 +0200] "POST /fg_scan HTTP/1.1" 200 32711 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14467
|
||||
192.168.0.132 - - [03/Nov/2025:15:50:11 +0200] "POST /fg_scan HTTP/1.1" 200 32720 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13977
|
||||
192.168.0.132 - - [03/Nov/2025:15:50:28 +0200] "POST /fg_scan HTTP/1.1" 200 32719 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12785
|
||||
192.168.0.132 - - [03/Nov/2025:15:50:47 +0200] "POST /fg_scan HTTP/1.1" 200 32718 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14669
|
||||
192.168.0.132 - - [03/Nov/2025:15:51:05 +0200] "POST /fg_scan HTTP/1.1" 200 32719 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14411
|
||||
192.168.0.132 - - [03/Nov/2025:15:51:32 +0200] "POST /fg_scan HTTP/1.1" 200 32722 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14472
|
||||
192.168.0.132 - - [03/Nov/2025:15:51:57 +0200] "POST /fg_scan HTTP/1.1" 200 32723 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14983
|
||||
192.168.0.132 - - [03/Nov/2025:15:52:17 +0200] "POST /fg_scan HTTP/1.1" 200 32724 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14828
|
||||
192.168.0.132 - - [03/Nov/2025:15:52:45 +0200] "POST /fg_scan HTTP/1.1" 200 32725 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 16130
|
||||
192.168.0.132 - - [03/Nov/2025:15:53:06 +0200] "POST /fg_scan HTTP/1.1" 200 32724 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13745
|
||||
192.168.0.132 - - [03/Nov/2025:15:53:21 +0200] "POST /fg_scan HTTP/1.1" 200 32723 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14353
|
||||
192.168.0.132 - - [03/Nov/2025:15:53:37 +0200] "POST /fg_scan HTTP/1.1" 200 32722 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14507
|
||||
192.168.0.132 - - [03/Nov/2025:15:53:53 +0200] "POST /fg_scan HTTP/1.1" 200 32721 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15300
|
||||
192.168.0.132 - - [03/Nov/2025:15:54:09 +0200] "POST /fg_scan HTTP/1.1" 200 32720 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 40809
|
||||
192.168.0.132 - - [03/Nov/2025:15:54:29 +0200] "POST /fg_scan HTTP/1.1" 200 32719 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15132
|
||||
192.168.0.132 - - [03/Nov/2025:15:54:47 +0200] "POST /fg_scan HTTP/1.1" 200 32717 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14832
|
||||
192.168.0.132 - - [03/Nov/2025:15:55:05 +0200] "POST /fg_scan HTTP/1.1" 200 32716 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 42256
|
||||
192.168.0.132 - - [03/Nov/2025:15:55:21 +0200] "POST /fg_scan HTTP/1.1" 200 32715 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15012
|
||||
192.168.0.132 - - [03/Nov/2025:15:55:34 +0200] "POST /fg_scan HTTP/1.1" 200 32724 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15096
|
||||
192.168.0.132 - - [03/Nov/2025:15:55:46 +0200] "POST /fg_scan HTTP/1.1" 200 32724 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14369
|
||||
192.168.0.132 - - [03/Nov/2025:15:56:03 +0200] "POST /fg_scan HTTP/1.1" 200 32723 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15199
|
||||
192.168.0.132 - - [03/Nov/2025:15:56:20 +0200] "POST /fg_scan HTTP/1.1" 200 32724 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15271
|
||||
192.168.0.132 - - [03/Nov/2025:15:57:37 +0200] "POST /fg_scan HTTP/1.1" 200 32724 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14363
|
||||
192.168.0.132 - - [03/Nov/2025:15:58:05 +0200] "POST /fg_scan HTTP/1.1" 200 32725 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14496
|
||||
192.168.0.132 - - [03/Nov/2025:15:58:20 +0200] "POST /fg_scan HTTP/1.1" 200 32726 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15623
|
||||
192.168.0.132 - - [03/Nov/2025:15:58:38 +0200] "POST /fg_scan HTTP/1.1" 200 32727 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13830
|
||||
192.168.0.132 - - [03/Nov/2025:15:58:52 +0200] "POST /fg_scan HTTP/1.1" 200 32728 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14584
|
||||
192.168.0.132 - - [03/Nov/2025:15:59:07 +0200] "POST /fg_scan HTTP/1.1" 200 32729 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14538
|
||||
192.168.0.132 - - [03/Nov/2025:15:59:26 +0200] "POST /fg_scan HTTP/1.1" 200 32730 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15633
|
||||
192.168.0.132 - - [03/Nov/2025:15:59:38 +0200] "POST /fg_scan HTTP/1.1" 200 32731 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15577
|
||||
192.168.0.132 - - [03/Nov/2025:15:59:53 +0200] "POST /fg_scan HTTP/1.1" 200 32732 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15506
|
||||
192.168.0.132 - - [03/Nov/2025:16:00:07 +0200] "POST /fg_scan HTTP/1.1" 200 32732 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13844
|
||||
192.168.0.132 - - [03/Nov/2025:16:00:17 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2706
|
||||
192.168.0.132 - - [03/Nov/2025:16:00:19 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2625
|
||||
192.168.0.132 - - [03/Nov/2025:16:00:23 +0200] "GET /fg_quality HTTP/1.1" 200 22317 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2857
|
||||
192.168.0.132 - - [03/Nov/2025:16:00:25 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 6944 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9772
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:48 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8172
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:48 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2737
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:48 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2526
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:48 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2581
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:48 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2487
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:49 +0200] "GET /quality HTTP/1.1" 200 8731 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2649
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:52 +0200] "GET /reports HTTP/1.1" 200 3277 "https://quality.moto-adv.com/quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2659
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:54 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2779
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:56 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2676
|
||||
192.168.0.132 - - [03/Nov/2025:17:41:58 +0200] "GET /fg_scan HTTP/1.1" 200 32732 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6455
|
||||
192.168.0.132 - - [03/Nov/2025:17:42:36 +0200] "POST /fg_scan HTTP/1.1" 200 32731 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14407
|
||||
192.168.0.132 - - [03/Nov/2025:17:42:54 +0200] "POST /fg_scan HTTP/1.1" 200 32730 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15836
|
||||
192.168.0.132 - - [03/Nov/2025:17:43:17 +0200] "POST /fg_scan HTTP/1.1" 200 32728 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15007
|
||||
192.168.0.132 - - [03/Nov/2025:17:43:36 +0200] "POST /fg_scan HTTP/1.1" 200 32727 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 15207
|
||||
192.168.0.132 - - [03/Nov/2025:17:44:02 +0200] "POST /fg_scan HTTP/1.1" 200 32725 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14736
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1444
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1669
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1983
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1853
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1734
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1750
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1951
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:40 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1447
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:41 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5228
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:41 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2347
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:41 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2302
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:42 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2245
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:43 +0200] "GET /fg_scan HTTP/1.1" 200 32725 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5854
|
||||
192.168.0.132 - - [03/Nov/2025:17:48:43 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2305
|
||||
192.168.0.132 - - [03/Nov/2025:17:50:38 +0200] "POST /fg_scan HTTP/1.1" 200 32723 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13769
|
||||
192.168.0.132 - - [03/Nov/2025:17:56:04 +0200] "POST /fg_scan HTTP/1.1" 200 32721 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13391
|
||||
192.168.0.132 - - [03/Nov/2025:17:56:56 +0200] "POST /fg_scan HTTP/1.1" 200 32720 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13891
|
||||
192.168.0.132 - - [03/Nov/2025:17:57:16 +0200] "POST /fg_scan HTTP/1.1" 200 32719 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13604
|
||||
192.168.0.132 - - [03/Nov/2025:17:58:01 +0200] "POST /fg_scan HTTP/1.1" 200 32718 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14025
|
||||
192.168.0.132 - - [03/Nov/2025:17:58:55 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1436
|
||||
192.168.0.132 - - [03/Nov/2025:17:58:55 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1670
|
||||
192.168.0.132 - - [03/Nov/2025:17:58:59 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5258
|
||||
192.168.0.132 - - [03/Nov/2025:17:58:59 +0200] "GET /dashboard HTTP/1.1" 200 2932 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2338
|
||||
192.168.0.132 - - [03/Nov/2025:17:59:04 +0200] "GET /main_scan HTTP/1.1" 200 2433 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2193
|
||||
192.168.0.132 - - [03/Nov/2025:17:59:09 +0200] "GET /fg_scan HTTP/1.1" 200 32718 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5883
|
||||
192.168.0.132 - - [03/Nov/2025:17:59:55 +0200] "POST /fg_scan HTTP/1.1" 200 32728 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13915
|
||||
192.168.0.132 - - [03/Nov/2025:18:31:25 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1991
|
||||
192.168.0.132 - - [03/Nov/2025:18:31:25 +0200] "GET / HTTP/1.1" 200 1627 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2071
|
||||
192.168.0.132 - - [03/Nov/2025:18:31:25 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2312
|
||||
192.168.0.132 - - [03/Nov/2025:18:31:25 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2293
|
||||
192.168.0.132 - - [03/Nov/2025:18:31:25 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1725
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 61988
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12865
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2025
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 27863
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 27549
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 29128
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:12 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2657
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:17 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 11441
|
||||
192.168.0.132 - - [03/Nov/2025:18:52:17 +0200] "GET /dashboard HTTP/1.1" 500 265 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 79088
|
||||
192.168.0.132 - - [03/Nov/2025:19:13:56 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 63622
|
||||
192.168.0.132 - - [03/Nov/2025:19:13:59 +0200] "GET /static/style.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 27903
|
||||
192.168.0.132 - - [03/Nov/2025:19:14:01 +0200] "GET /js/lkk_ch.js HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 17892
|
||||
192.168.0.132 - - [03/Nov/2025:19:14:09 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 13426
|
||||
192.168.0.132 - - [03/Nov/2025:19:14:12 +0200] "GET /css/support_parent.css HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 1465
|
||||
192.168.0.132 - - [03/Nov/2025:19:14:12 +0200] "GET /static/script.js HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 28210
|
||||
192.168.0.132 - - [03/Nov/2025:19:14:15 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36" 15437
|
||||
127.0.0.1 - - [03/Nov/2025:19:32:05 +0200] "GET / HTTP/1.1" 200 1688 "-" "curl/8.14.1" 49996
|
||||
127.0.0.1 - - [03/Nov/2025:19:34:59 +0200] "GET / HTTP/1.1" 200 1688 "-" "curl/8.14.1" 61225 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:36:05 +0200] "GET /dashboard HTTP/1.1" 500 265 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 94788 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:36:08 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 9191 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:36:23 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 26201 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:36:23 +0200] "GET /dashboard HTTP/1.1" 500 265 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 79185 µs
|
||||
127.0.0.1 - - [03/Nov/2025:19:38:11 +0200] "GET / HTTP/1.1" 200 1688 "-" "curl/8.14.1" 2159 µs
|
||||
127.0.0.1 - - [03/Nov/2025:19:42:47 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "curl/8.14.1" 17041 µs
|
||||
127.0.0.1 - - [03/Nov/2025:19:43:40 +0200] "POST / HTTP/1.1" 200 1688 "-" "curl/8.14.1" 73782 µs
|
||||
127.0.0.1 - - [03/Nov/2025:19:44:26 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "curl/8.14.1" 20144 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:44:55 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 70205 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:44:55 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 13018 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:17 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 64331 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:19 +0200] "GET /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 36225 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:19 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12443 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:32 +0200] "GET /reports HTTP/1.1" 200 3388 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 8148 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:36 +0200] "GET /fg_quality HTTP/1.1" 200 22444 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 21915 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:36 +0200] "GET /static/fg_quality.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2608 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:38 +0200] "GET /get_fg_report_data?report=1 HTTP/1.1" 200 4791 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 9459 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:46:52 +0200] "GET /settings HTTP/1.1" 200 10625 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 29667 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:47:14 +0200] "GET /user_management_simple HTTP/1.1" 200 43577 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 54731 µs
|
||||
192.168.0.132 - - [03/Nov/2025:19:55:16 +0200] "GET /user_management_simple HTTP/1.1" 200 43577 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 113978 µs
|
||||
803
logs/error.log
@@ -1,201 +0,0 @@
|
||||
# Print Module CSS Modularization - Summary
|
||||
|
||||
## What was accomplished
|
||||
|
||||
### 1. Created Modular CSS File
|
||||
- **File**: `/srv/quality_recticel/py_app/app/static/css/print_module.css`
|
||||
- **Purpose**: Centralized CSS for all printing module pages
|
||||
- **Size**: 610 lines of well-organized, documented CSS
|
||||
|
||||
### 2. Pages Affected
|
||||
The following templates now use the modular CSS instead of embedded styles:
|
||||
|
||||
- ✅ `print_module.html` - Main printing interface
|
||||
- ✅ `print_lost_labels.html` - Lost labels printing
|
||||
- ✅ `view_orders.html` - View uploaded orders
|
||||
- ✅ `upload_orders.html` - Upload order data
|
||||
- ✅ `main_page_etichete.html` - Labels main page (already clean)
|
||||
|
||||
### 3. CSS Organization Structure
|
||||
|
||||
```css
|
||||
/* ==========================================================================
|
||||
LABEL PREVIEW STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT MODULE TABLE STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
VIEW ORDERS TABLE STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT MODULE LAYOUT STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
SEARCH AND FORM STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
BUTTON STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT OPTIONS STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
THEME SUPPORT (Light/Dark Mode)
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
RESPONSIVE DESIGN
|
||||
========================================================================== */
|
||||
```
|
||||
|
||||
### 4. Base Template Integration
|
||||
- **File**: `base.html`
|
||||
- **Added**: Conditional CSS loading for printing module pages
|
||||
- **Logic**: CSS only loads for printing-related endpoints
|
||||
|
||||
```html
|
||||
<!-- Print Module CSS for Labels/Printing pages -->
|
||||
{% if request.endpoint in ['main.etichete', 'main.upload_data', 'main.view_orders', 'main.print_module', 'main.print_lost_labels'] %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/print_module.css') }}">
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
### 5. Template Cleanup
|
||||
- **Before**: Each template had 50-100+ lines of embedded CSS
|
||||
- **After**: Clean templates with `<!-- Print Module CSS is now loaded via base.html -->`
|
||||
- **Removed**: ~400 lines of duplicate CSS across templates
|
||||
|
||||
### 6. CSS Features Preserved
|
||||
All original functionality maintained:
|
||||
|
||||
✅ **Label Preview Styling**
|
||||
- Label layout with precise positioning
|
||||
- Barcode frames (horizontal & vertical)
|
||||
- SVG barcode styling with forced black colors
|
||||
|
||||
✅ **Table Styling**
|
||||
- Print module tables with dark theme support
|
||||
- View orders tables with column width specifications
|
||||
- Hover effects and selection styling
|
||||
|
||||
✅ **Responsive Design**
|
||||
- Mobile-friendly layouts
|
||||
- Flexible container widths
|
||||
- Adaptive label preview sizing
|
||||
|
||||
✅ **Theme Support**
|
||||
- Light/dark mode compatibility
|
||||
- CSS custom properties for theming
|
||||
- Proper color contrast
|
||||
|
||||
✅ **Print Options UI**
|
||||
- QZ Tray integration styling
|
||||
- Printer selection dropdowns
|
||||
- Status badges and indicators
|
||||
|
||||
### 7. Benefits Achieved
|
||||
|
||||
#### Maintainability
|
||||
- ✅ Single source of truth for printing module styles
|
||||
- ✅ Easy to find and modify styles
|
||||
- ✅ No more hunting through multiple templates
|
||||
- ✅ Consistent styling across all pages
|
||||
|
||||
#### Performance
|
||||
- ✅ CSS only loads when needed (conditional loading)
|
||||
- ✅ Reduced template size and complexity
|
||||
- ✅ Browser caching of CSS file
|
||||
|
||||
#### Development Experience
|
||||
- ✅ Well-organized, commented code
|
||||
- ✅ Clear section separators
|
||||
- ✅ Logical grouping of related styles
|
||||
- ✅ Debug utilities included
|
||||
|
||||
#### Code Quality
|
||||
- ✅ Eliminated duplicate CSS
|
||||
- ✅ Consistent naming conventions
|
||||
- ✅ Proper CSS methodology
|
||||
- ✅ Clean template structure
|
||||
|
||||
### 8. File Structure After Changes
|
||||
|
||||
```
|
||||
/srv/quality_recticel/py_app/app/
|
||||
├── static/
|
||||
│ └── css/
|
||||
│ ├── base.css (existing)
|
||||
│ ├── print_module.css (NEW - 610 lines)
|
||||
│ └── other.css files...
|
||||
└── templates/
|
||||
├── base.html (updated with conditional CSS loading)
|
||||
├── print_module.html (cleaned up)
|
||||
├── print_lost_labels.html (cleaned up)
|
||||
├── view_orders.html (cleaned up)
|
||||
├── upload_orders.html (cleaned up)
|
||||
└── main_page_etichete.html (already clean)
|
||||
```
|
||||
|
||||
### 9. Testing Results
|
||||
- ✅ Flask application running successfully on port 8782
|
||||
- ✅ All printing module pages loading without errors
|
||||
- ✅ CSS being served correctly (304 cached responses)
|
||||
- ✅ Label Module navigation working properly
|
||||
- ✅ Print functionality operational
|
||||
- ✅ No breaking changes to existing features
|
||||
|
||||
### 10. Future Maintenance
|
||||
|
||||
#### Adding New Styles
|
||||
1. Open `/srv/quality_recticel/py_app/app/static/css/print_module.css`
|
||||
2. Find appropriate section or create new one
|
||||
3. Add styles with proper comments
|
||||
4. Test on all affected pages
|
||||
|
||||
#### Modifying Existing Styles
|
||||
1. Use browser dev tools to identify CSS rule
|
||||
2. Update in print_module.css instead of templates
|
||||
3. Changes apply to all printing pages automatically
|
||||
|
||||
#### Debugging CSS Issues
|
||||
1. Check browser dev tools for CSS loading
|
||||
2. Look for 404 errors on CSS file
|
||||
3. Verify conditional loading logic in base.html
|
||||
4. Use debug classes provided in CSS file
|
||||
|
||||
### 11. Code Quality Improvements
|
||||
|
||||
#### Before (per template):
|
||||
```html
|
||||
{% block head %}
|
||||
<style>
|
||||
/* 50-100 lines of CSS mixed with HTML */
|
||||
table.view-orders-table.scan-table { ... }
|
||||
/* More styles... */
|
||||
</style>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
#### After (centralized):
|
||||
```html
|
||||
{% block head %}
|
||||
<!-- Print Module CSS is now loaded via base.html for all printing pages -->
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
#### CSS File:
|
||||
```css
|
||||
/* ==========================================================================
|
||||
WELL ORGANIZED SECTIONS WITH CLEAR DOCUMENTATION
|
||||
========================================================================== */
|
||||
```
|
||||
|
||||
This modularization makes the printing module much more maintainable and follows CSS best practices for large applications.
|
||||
@@ -1,155 +0,0 @@
|
||||
# Print Module Theme System Implementation
|
||||
|
||||
## ✅ **Theme Support Successfully Implemented**
|
||||
|
||||
### **CSS Custom Properties System**
|
||||
|
||||
I've implemented a comprehensive theme system using CSS custom properties (CSS variables) that automatically adapts all tables and UI elements in the printing module to match the selected theme (light/dark mode).
|
||||
|
||||
### **Theme Variables Defined**
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Light mode colors (default) */
|
||||
--print-table-header-bg: #e9ecef;
|
||||
--print-table-header-text: #000;
|
||||
--print-table-body-bg: #fff;
|
||||
--print-table-body-text: #000;
|
||||
--print-table-border: #ddd;
|
||||
--print-table-hover: #f8f9fa;
|
||||
--print-table-selected: #007bff;
|
||||
--print-card-bg: #fff;
|
||||
--print-card-border: #ddd;
|
||||
--print-search-field-bg: #fff;
|
||||
--print-search-field-text: #000;
|
||||
--print-search-field-border: #ddd;
|
||||
}
|
||||
```
|
||||
|
||||
### **Light Mode Theme**
|
||||
```css
|
||||
body.light-mode {
|
||||
--print-table-header-bg: #e9ecef; /* Light gray headers */
|
||||
--print-table-header-text: #000; /* Black text */
|
||||
--print-table-body-bg: #fff; /* White background */
|
||||
--print-table-body-text: #000; /* Black text */
|
||||
--print-table-border: #ddd; /* Light gray borders */
|
||||
--print-table-hover: #f8f9fa; /* Very light gray hover */
|
||||
--print-card-bg: #fff; /* White cards */
|
||||
}
|
||||
```
|
||||
|
||||
### **Dark Mode Theme**
|
||||
```css
|
||||
body.dark-mode {
|
||||
--print-table-header-bg: #2a3441; /* Dark blue-gray headers */
|
||||
--print-table-header-text: #ffffff; /* White text */
|
||||
--print-table-body-bg: #2a3441; /* Dark blue-gray background */
|
||||
--print-table-body-text: #ffffff; /* White text */
|
||||
--print-table-border: #495057; /* Medium gray borders */
|
||||
--print-table-hover: #3a4451; /* Lighter dark gray hover */
|
||||
--print-card-bg: #2a2a2a; /* Dark gray cards */
|
||||
}
|
||||
```
|
||||
|
||||
### **Components That Respond to Theme**
|
||||
|
||||
#### ✅ **View Orders Table**
|
||||
- **Headers**: Background and text color change automatically
|
||||
- **Body cells**: Background, text, and border colors adapt
|
||||
- **Hover effects**: Appropriate hover colors for each theme
|
||||
- **Selected rows**: Consistent selection highlighting
|
||||
|
||||
#### ✅ **Print Module Table**
|
||||
- **Headers**: Theme-aware colors and borders
|
||||
- **Data cells**: Proper contrast in both themes
|
||||
- **Row interactions**: Hover and selection states
|
||||
- **Border consistency**: Unified border styling
|
||||
|
||||
#### ✅ **Upload Orders Table**
|
||||
- **Same styling system**: Uses shared CSS variables
|
||||
- **Consistent appearance**: Matches other tables
|
||||
- **Theme transitions**: Smooth switching between themes
|
||||
|
||||
#### ✅ **Cards and Forms**
|
||||
- **Background colors**: Adapt to theme
|
||||
- **Border colors**: Consistent with theme palette
|
||||
- **Search fields**: Proper contrast and visibility
|
||||
- **Form elements**: Theme-aware styling
|
||||
|
||||
#### ✅ **Label Preview**
|
||||
- **Preview backgrounds**: Appropriate for each theme
|
||||
- **Barcode frames**: Maintains visibility in both modes
|
||||
- **Text contrast**: Ensures readability
|
||||
|
||||
### **How Theme Switching Works**
|
||||
|
||||
1. **Automatic Detection**: The system detects `body.light-mode` or `body.dark-mode` class
|
||||
2. **Variable Updates**: CSS custom properties automatically update based on the body class
|
||||
3. **Instant Application**: All elements using the variables immediately reflect the new theme
|
||||
4. **No JavaScript Required**: Pure CSS implementation for better performance
|
||||
|
||||
### **Benefits Achieved**
|
||||
|
||||
#### ✅ **Consistent Design**
|
||||
- All printing module tables have unified styling
|
||||
- Colors are coordinated across all components
|
||||
- Professional appearance in both themes
|
||||
|
||||
#### ✅ **Better User Experience**
|
||||
- **Light Mode**: Clean, bright interface for well-lit environments
|
||||
- **Dark Mode**: Easy on the eyes for low-light conditions
|
||||
- **Smooth Transitions**: No jarring color mismatches when switching
|
||||
|
||||
#### ✅ **Accessibility**
|
||||
- **High Contrast**: Proper contrast ratios in both themes
|
||||
- **Color Consistency**: Related elements use the same color palette
|
||||
- **Visual Hierarchy**: Headers clearly distinguished from content
|
||||
|
||||
#### ✅ **Maintainability**
|
||||
- **Single Source of Truth**: All theme colors defined in one place
|
||||
- **Easy Updates**: Change a variable to update all occurrences
|
||||
- **Scalable**: Easy to add new components or themes
|
||||
|
||||
### **Visual Comparison**
|
||||
|
||||
#### Light Mode
|
||||
- **Table Headers**: Light gray background (#e9ecef) with black text
|
||||
- **Table Bodies**: White background with black text
|
||||
- **Borders**: Light gray (#ddd) for subtle separation
|
||||
- **Hover**: Very light gray (#f8f9fa) for subtle feedback
|
||||
- **Cards**: Clean white backgrounds
|
||||
|
||||
#### Dark Mode
|
||||
- **Table Headers**: Dark blue-gray (#2a3441) with white text
|
||||
- **Table Bodies**: Dark blue-gray background with white text
|
||||
- **Borders**: Medium gray (#495057) for proper separation
|
||||
- **Hover**: Lighter dark gray (#3a4451) for clear feedback
|
||||
- **Cards**: Dark gray backgrounds for reduced eye strain
|
||||
|
||||
### **Pages Affected**
|
||||
|
||||
✅ **view_orders.html** - Orders listing with improved 25/75 layout
|
||||
✅ **print_module.html** - Main printing interface
|
||||
✅ **print_lost_labels.html** - Lost labels printing
|
||||
✅ **upload_orders.html** - Order upload interface
|
||||
✅ **main_page_etichete.html** - Labels main page
|
||||
|
||||
### **Technical Implementation**
|
||||
|
||||
The theme system works by:
|
||||
|
||||
1. **CSS Variables**: Using `var(--variable-name)` throughout the stylesheets
|
||||
2. **Body Classes**: Theme variables update based on `body.light-mode` / `body.dark-mode`
|
||||
3. **Automatic Inheritance**: All child elements inherit the appropriate theme
|
||||
4. **Performance**: No JavaScript overhead, pure CSS solution
|
||||
|
||||
### **Testing Confirmed**
|
||||
|
||||
- ✅ Theme switching works instantly
|
||||
- ✅ All tables respond to theme changes
|
||||
- ✅ No visual inconsistencies
|
||||
- ✅ Proper contrast in both modes
|
||||
- ✅ Layout remains stable during theme switches
|
||||
|
||||
The printing module now provides a professional, consistent, and accessible user interface that adapts beautifully to both light and dark themes!
|
||||
@@ -1,133 +0,0 @@
|
||||
# Quick Database Setup for Trasabilitate Application
|
||||
|
||||
This script provides a complete one-step database setup for quick deployment of the Trasabilitate application.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before running the setup script, ensure:
|
||||
|
||||
1. **MariaDB is installed and running**
|
||||
2. **Database and user are created**:
|
||||
```sql
|
||||
CREATE DATABASE trasabilitate;
|
||||
CREATE USER 'trasabilitate'@'localhost' IDENTIFIED BY 'Initial01!';
|
||||
GRANT ALL PRIVILEGES ON trasabilitate.* TO 'trasabilitate'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
3. **Python virtual environment is activated**:
|
||||
```bash
|
||||
source ../recticel/bin/activate
|
||||
```
|
||||
4. **Python dependencies are installed**:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Quick Setup (Recommended)
|
||||
```bash
|
||||
cd /srv/quality_recticel/py_app
|
||||
source ../recticel/bin/activate
|
||||
python3 app/db_create_scripts/setup_complete_database.py
|
||||
```
|
||||
|
||||
### What the script creates:
|
||||
|
||||
#### MariaDB Tables:
|
||||
- `scan1_orders` - Quality scanning data for process 1
|
||||
- `scanfg_orders` - Quality scanning data for finished goods
|
||||
- `order_for_labels` - Label printing orders
|
||||
- `warehouse_locations` - Warehouse location management
|
||||
- `permissions` - System permissions
|
||||
- `role_permissions` - Role-permission mappings
|
||||
- `role_hierarchy` - User role hierarchy
|
||||
- `permission_audit_log` - Permission change audit trail
|
||||
|
||||
#### Database Triggers:
|
||||
- Auto-increment approved/rejected quantities based on quality codes
|
||||
- Triggers for both scan1_orders and scanfg_orders tables
|
||||
|
||||
#### SQLite Tables:
|
||||
- `users` - User authentication (in instance/users.db)
|
||||
- `roles` - User roles (in instance/users.db)
|
||||
|
||||
#### Configuration:
|
||||
- Updates `instance/external_server.conf` with correct database settings
|
||||
- Creates default superadmin user (username: `superadmin`, password: `superadmin123`)
|
||||
|
||||
#### Permission System:
|
||||
- 7 user roles (superadmin, admin, manager, quality_manager, warehouse_manager, quality_worker, warehouse_worker)
|
||||
- 25+ granular permissions for different application areas
|
||||
- Complete role hierarchy with inheritance
|
||||
|
||||
## After Setup
|
||||
|
||||
1. **Start the application**:
|
||||
```bash
|
||||
python3 run.py
|
||||
```
|
||||
|
||||
2. **Access the application**:
|
||||
- Local: http://127.0.0.1:8781
|
||||
- Network: http://192.168.0.205:8781
|
||||
|
||||
3. **Login with superadmin**:
|
||||
- Username: `superadmin`
|
||||
- Password: `superadmin123`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues:
|
||||
|
||||
1. **Database connection failed**:
|
||||
- Check if MariaDB is running: `sudo systemctl status mariadb`
|
||||
- Verify database exists: `sudo mysql -e "SHOW DATABASES;"`
|
||||
- Check user privileges: `sudo mysql -e "SHOW GRANTS FOR 'trasabilitate'@'localhost';"`
|
||||
|
||||
2. **Import errors**:
|
||||
- Ensure virtual environment is activated
|
||||
- Install missing dependencies: `pip install -r requirements.txt`
|
||||
|
||||
3. **Permission denied**:
|
||||
- Make script executable: `chmod +x app/db_create_scripts/setup_complete_database.py`
|
||||
- Check file ownership: `ls -la app/db_create_scripts/`
|
||||
|
||||
### Manual Database Recreation:
|
||||
|
||||
If you need to completely reset the database:
|
||||
|
||||
```bash
|
||||
# Drop and recreate database
|
||||
sudo mysql -e "DROP DATABASE IF EXISTS trasabilitate; CREATE DATABASE trasabilitate; GRANT ALL PRIVILEGES ON trasabilitate.* TO 'trasabilitate'@'localhost'; FLUSH PRIVILEGES;"
|
||||
|
||||
# Remove SQLite database
|
||||
rm -f instance/users.db
|
||||
|
||||
# Run setup script
|
||||
python3 app/db_create_scripts/setup_complete_database.py
|
||||
```
|
||||
|
||||
## Script Features
|
||||
|
||||
- ✅ **Comprehensive**: Creates all necessary database structure
|
||||
- ✅ **Safe**: Uses `IF NOT EXISTS` clauses to prevent conflicts
|
||||
- ✅ **Verified**: Includes verification step to confirm setup
|
||||
- ✅ **Informative**: Detailed output showing each step
|
||||
- ✅ **Error handling**: Clear error messages and troubleshooting hints
|
||||
- ✅ **Idempotent**: Can be run multiple times safely
|
||||
|
||||
## Development Notes
|
||||
|
||||
The script combines functionality from these individual scripts:
|
||||
- `create_scan_1db.py`
|
||||
- `create_scanfg_orders.py`
|
||||
- `create_order_for_labels_table.py`
|
||||
- `create_warehouse_locations_table.py`
|
||||
- `create_permissions_tables.py`
|
||||
- `create_roles_table.py`
|
||||
- `create_triggers.py`
|
||||
- `create_triggers_fg.py`
|
||||
- `populate_permissions.py`
|
||||
|
||||
For development or debugging, you can still run individual scripts if needed.
|
||||
@@ -1,319 +0,0 @@
|
||||
# Recticel Quality Application - Docker Deployment Guide
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
This is a complete Docker-based deployment solution for the Recticel Quality Application. It includes:
|
||||
- **Flask Web Application** (Python 3.10)
|
||||
- **MariaDB 11.3 Database** with automatic initialization
|
||||
- **Gunicorn WSGI Server** for production-ready performance
|
||||
- **Automatic database schema setup** using existing setup scripts
|
||||
- **Superadmin user seeding** for immediate access
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- Docker Engine 20.10+
|
||||
- Docker Compose 2.0+
|
||||
- At least 2GB free disk space
|
||||
- Ports 8781 and 3306 available (or customize in .env)
|
||||
|
||||
### 1. Clone and Prepare
|
||||
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
```
|
||||
|
||||
### 2. Configure Environment (Optional)
|
||||
|
||||
Create a `.env` file from the example:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Edit `.env` to customize settings:
|
||||
```env
|
||||
MYSQL_ROOT_PASSWORD=your_secure_root_password
|
||||
DB_PORT=3306
|
||||
APP_PORT=8781
|
||||
INIT_DB=true
|
||||
SEED_DB=true
|
||||
```
|
||||
|
||||
### 3. Build and Deploy
|
||||
|
||||
Start all services:
|
||||
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
This will:
|
||||
1. ✅ Build the Flask application Docker image
|
||||
2. ✅ Pull MariaDB 11.3 image
|
||||
3. ✅ Create and initialize the database
|
||||
4. ✅ Run all database schema creation scripts
|
||||
5. ✅ Seed the superadmin user
|
||||
6. ✅ Start the web application on port 8781
|
||||
|
||||
### 4. Verify Deployment
|
||||
|
||||
Check service status:
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
View logs:
|
||||
```bash
|
||||
# All services
|
||||
docker-compose logs -f
|
||||
|
||||
# Just the web app
|
||||
docker-compose logs -f web
|
||||
|
||||
# Just the database
|
||||
docker-compose logs -f db
|
||||
```
|
||||
|
||||
### 5. Access the Application
|
||||
|
||||
Open your browser and navigate to:
|
||||
```
|
||||
http://localhost:8781
|
||||
```
|
||||
|
||||
**Default Login:**
|
||||
- Username: `superadmin`
|
||||
- Password: `superadmin123`
|
||||
|
||||
## 🔧 Management Commands
|
||||
|
||||
### Start Services
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Stop Services
|
||||
```bash
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
### Stop and Remove All Data (including database)
|
||||
```bash
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
### Restart Services
|
||||
```bash
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
### View Real-time Logs
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### Rebuild After Code Changes
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
### Access Database Console
|
||||
```bash
|
||||
docker-compose exec db mariadb -u trasabilitate -p trasabilitate
|
||||
# Password: Initial01!
|
||||
```
|
||||
|
||||
### Execute Commands in App Container
|
||||
```bash
|
||||
docker-compose exec web bash
|
||||
```
|
||||
|
||||
## 📁 Data Persistence
|
||||
|
||||
The following data is persisted across container restarts:
|
||||
|
||||
- **Database Data:** Stored in Docker volume `mariadb_data`
|
||||
- **Application Logs:** Mapped to `./logs` directory
|
||||
- **Instance Config:** Mapped to `./instance` directory
|
||||
|
||||
## 🔐 Security Considerations
|
||||
|
||||
### Production Deployment Checklist:
|
||||
|
||||
1. **Change Default Passwords:**
|
||||
- Update `MYSQL_ROOT_PASSWORD` in `.env`
|
||||
- Update database password in `docker-compose.yml`
|
||||
- Change superadmin password after first login
|
||||
|
||||
2. **Use Environment Variables:**
|
||||
- Never commit `.env` file to version control
|
||||
- Use secrets management for production
|
||||
|
||||
3. **Network Security:**
|
||||
- If database access from host is not needed, remove the port mapping:
|
||||
```yaml
|
||||
# Comment out in docker-compose.yml:
|
||||
# ports:
|
||||
# - "3306:3306"
|
||||
```
|
||||
|
||||
4. **SSL/TLS:**
|
||||
- Configure reverse proxy (nginx/traefik) for HTTPS
|
||||
- Update gunicorn SSL configuration if needed
|
||||
|
||||
5. **Firewall:**
|
||||
- Only expose necessary ports
|
||||
- Use firewall rules to restrict access
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
If the app can't connect to the database:
|
||||
|
||||
```bash
|
||||
# Check database health
|
||||
docker-compose exec db healthcheck.sh --connect
|
||||
|
||||
# Check database logs
|
||||
docker-compose logs db
|
||||
|
||||
# Verify database is accessible
|
||||
docker-compose exec db mariadb -u trasabilitate -p -e "SHOW DATABASES;"
|
||||
```
|
||||
|
||||
### Application Not Starting
|
||||
|
||||
```bash
|
||||
# Check application logs
|
||||
docker-compose logs web
|
||||
|
||||
# Verify database initialization
|
||||
docker-compose exec web python3 -c "import mariadb; print('MariaDB module OK')"
|
||||
|
||||
# Restart with fresh initialization
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
If port 8781 or 3306 is already in use, edit `.env`:
|
||||
|
||||
```env
|
||||
APP_PORT=8782
|
||||
DB_PORT=3307
|
||||
```
|
||||
|
||||
Then restart:
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Reset Everything
|
||||
|
||||
To start completely fresh:
|
||||
|
||||
```bash
|
||||
# Stop and remove all containers, networks, and volumes
|
||||
docker-compose down -v
|
||||
|
||||
# Remove any local data
|
||||
rm -rf logs/* instance/external_server.conf
|
||||
|
||||
# Start fresh
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## 🔄 Updating the Application
|
||||
|
||||
### Update Application Code
|
||||
|
||||
1. Make your code changes
|
||||
2. Rebuild and restart:
|
||||
```bash
|
||||
docker-compose up -d --build web
|
||||
```
|
||||
|
||||
### Update Database Schema
|
||||
|
||||
If you need to run migrations or schema updates:
|
||||
|
||||
```bash
|
||||
docker-compose exec web python3 /app/app/db_create_scripts/setup_complete_database.py
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Health Checks
|
||||
|
||||
Both services have health checks configured:
|
||||
|
||||
```bash
|
||||
# Check overall status
|
||||
docker-compose ps
|
||||
|
||||
# Detailed health status
|
||||
docker inspect recticel-app | grep -A 10 Health
|
||||
docker inspect recticel-db | grep -A 10 Health
|
||||
```
|
||||
|
||||
### Resource Usage
|
||||
|
||||
```bash
|
||||
# View resource consumption
|
||||
docker stats recticel-app recticel-db
|
||||
```
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Docker Compose Network │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌─────────────┐ │
|
||||
│ │ MariaDB │ │ Flask App │ │
|
||||
│ │ Container │◄─┤ Container │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ Port: 3306 │ │ Port: 8781 │ │
|
||||
│ └──────┬───────┘ └──────┬──────┘ │
|
||||
│ │ │ │
|
||||
└─────────┼─────────────────┼─────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
[Volume: [Logs &
|
||||
mariadb_data] Instance]
|
||||
```
|
||||
|
||||
## 📝 Environment Variables
|
||||
|
||||
### Database Configuration
|
||||
- `MYSQL_ROOT_PASSWORD`: MariaDB root password
|
||||
- `DB_HOST`: Database hostname (default: `db`)
|
||||
- `DB_PORT`: Database port (default: `3306`)
|
||||
- `DB_NAME`: Database name (default: `trasabilitate`)
|
||||
- `DB_USER`: Database user (default: `trasabilitate`)
|
||||
- `DB_PASSWORD`: Database password (default: `Initial01!`)
|
||||
|
||||
### Application Configuration
|
||||
- `FLASK_ENV`: Flask environment (default: `production`)
|
||||
- `FLASK_APP`: Flask app entry point (default: `run.py`)
|
||||
- `APP_PORT`: Application port (default: `8781`)
|
||||
|
||||
### Initialization Flags
|
||||
- `INIT_DB`: Run database initialization (default: `true`)
|
||||
- `SEED_DB`: Seed superadmin user (default: `true`)
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
For issues or questions:
|
||||
1. Check the logs: `docker-compose logs -f`
|
||||
2. Verify environment configuration
|
||||
3. Ensure all prerequisites are met
|
||||
4. Review this documentation
|
||||
|
||||
## 📄 License
|
||||
|
||||
[Your License Here]
|
||||
@@ -1,346 +0,0 @@
|
||||
# Recticel Quality Application - Docker Solution Summary
|
||||
|
||||
## 📦 What Has Been Created
|
||||
|
||||
A complete, production-ready Docker deployment solution for your Recticel Quality Application with the following components:
|
||||
|
||||
### Core Files Created
|
||||
|
||||
1. **`Dockerfile`** - Multi-stage Flask application container
|
||||
- Based on Python 3.10-slim
|
||||
- Installs all dependencies from requirements.txt
|
||||
- Configures Gunicorn WSGI server
|
||||
- Exposes port 8781
|
||||
|
||||
2. **`docker-compose.yml`** - Complete orchestration configuration
|
||||
- MariaDB 11.3 database service
|
||||
- Flask web application service
|
||||
- Automatic networking between services
|
||||
- Health checks for both services
|
||||
- Volume persistence for database and logs
|
||||
|
||||
3. **`docker-entrypoint.sh`** - Smart initialization script
|
||||
- Waits for database to be ready
|
||||
- Creates database configuration file
|
||||
- Runs database schema initialization
|
||||
- Seeds superadmin user
|
||||
- Starts the application
|
||||
|
||||
4. **`init-db.sql`** - MariaDB initialization
|
||||
- Creates database and user
|
||||
- Sets up permissions automatically
|
||||
|
||||
5. **`.env.example`** - Configuration template
|
||||
- Database passwords
|
||||
- Port configurations
|
||||
- Initialization flags
|
||||
|
||||
6. **`.dockerignore`** - Build optimization
|
||||
- Excludes unnecessary files from Docker image
|
||||
- Reduces image size
|
||||
|
||||
7. **`deploy.sh`** - One-command deployment script
|
||||
- Checks prerequisites
|
||||
- Creates configuration
|
||||
- Builds and starts services
|
||||
- Shows deployment status
|
||||
|
||||
8. **`Makefile`** - Convenient management commands
|
||||
- `make install` - First-time installation
|
||||
- `make up` - Start services
|
||||
- `make down` - Stop services
|
||||
- `make logs` - View logs
|
||||
- `make shell` - Access container
|
||||
- `make backup-db` - Backup database
|
||||
- And many more...
|
||||
|
||||
9. **`DOCKER_DEPLOYMENT.md`** - Complete documentation
|
||||
- Quick start guide
|
||||
- Management commands
|
||||
- Troubleshooting
|
||||
- Security considerations
|
||||
- Architecture diagrams
|
||||
|
||||
### Enhanced Files
|
||||
|
||||
10. **`setup_complete_database.py`** - Updated to support Docker
|
||||
- Now reads from environment variables
|
||||
- Fallback to config file for non-Docker deployments
|
||||
- Maintains backward compatibility
|
||||
|
||||
## 🎯 Key Features
|
||||
|
||||
### 1. Single-Command Deployment
|
||||
```bash
|
||||
./deploy.sh
|
||||
```
|
||||
This single command will:
|
||||
- ✅ Build Docker images
|
||||
- ✅ Create MariaDB database
|
||||
- ✅ Initialize all database tables and triggers
|
||||
- ✅ Seed superadmin user
|
||||
- ✅ Start the application
|
||||
|
||||
### 2. Complete Isolation
|
||||
- Application runs in its own container
|
||||
- Database runs in its own container
|
||||
- No system dependencies needed except Docker
|
||||
- No Python/MariaDB installation on host required
|
||||
|
||||
### 3. Data Persistence
|
||||
- Database data persists across restarts (Docker volume)
|
||||
- Application logs accessible on host
|
||||
- Configuration preserved
|
||||
|
||||
### 4. Production Ready
|
||||
- Gunicorn WSGI server (not Flask dev server)
|
||||
- Health checks for monitoring
|
||||
- Automatic restart on failure
|
||||
- Proper logging configuration
|
||||
- Resource isolation
|
||||
|
||||
### 5. Easy Management
|
||||
```bash
|
||||
# Start
|
||||
docker compose up -d
|
||||
|
||||
# Stop
|
||||
docker compose down
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Backup database
|
||||
make backup-db
|
||||
|
||||
# Restore database
|
||||
make restore-db BACKUP=backup_20231215.sql
|
||||
|
||||
# Access shell
|
||||
make shell
|
||||
|
||||
# Complete reset
|
||||
make reset
|
||||
```
|
||||
|
||||
## 🚀 Deployment Options
|
||||
|
||||
### Option 1: Quick Deploy (Recommended for Testing)
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### Option 2: Using Makefile (Recommended for Management)
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
make install # First time only
|
||||
make up # Start services
|
||||
make logs # Monitor
|
||||
```
|
||||
|
||||
### Option 3: Using Docker Compose Directly
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
cp .env.example .env
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
The deployment **requires** Docker to be installed on the target system:
|
||||
|
||||
### Installing Docker on Ubuntu/Debian:
|
||||
```bash
|
||||
# Update package index
|
||||
sudo apt-get update
|
||||
|
||||
# Install dependencies
|
||||
sudo apt-get install -y ca-certificates curl gnupg
|
||||
|
||||
# Add Docker's official GPG key
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
|
||||
# Set up the repository
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
|
||||
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
# Install Docker Engine
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
# Add current user to docker group (optional, to run without sudo)
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
After installation, log out and back in for group changes to take effect.
|
||||
|
||||
### Installing Docker on CentOS/RHEL:
|
||||
```bash
|
||||
sudo yum install -y yum-utils
|
||||
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
||||
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ Docker Compose Stack │
|
||||
│ │
|
||||
│ ┌────────────────────┐ ┌───────────────────┐ │
|
||||
│ │ MariaDB 11.3 │ │ Flask App │ │
|
||||
│ │ Container │◄─────┤ Container │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ - Port: 3306 │ │ - Port: 8781 │ │
|
||||
│ │ - Volume: DB Data │ │ - Gunicorn WSGI │ │
|
||||
│ │ - Auto Init │ │ - Python 3.10 │ │
|
||||
│ │ - Health Checks │ │ - Health Checks │ │
|
||||
│ └──────────┬─────────┘ └─────────┬─────────┘ │
|
||||
│ │ │ │
|
||||
└─────────────┼──────────────────────────┼─────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
[mariadb_data] [logs directory]
|
||||
Docker Volume Host filesystem
|
||||
```
|
||||
|
||||
## 🔐 Security Features
|
||||
|
||||
1. **Database Isolation**: Database not exposed to host by default (can be configured)
|
||||
2. **Password Management**: All passwords in `.env` file (not committed to git)
|
||||
3. **User Permissions**: Proper MariaDB user with limited privileges
|
||||
4. **Network Isolation**: Services communicate on private Docker network
|
||||
5. **Production Mode**: Flask runs in production mode with Gunicorn
|
||||
|
||||
## 📊 What Gets Deployed
|
||||
|
||||
### Database Schema
|
||||
All tables from `setup_complete_database.py`:
|
||||
- `scan1_orders` - First scan orders
|
||||
- `scanfg_orders` - Final goods scan orders
|
||||
- `order_for_labels` - Label orders
|
||||
- `warehouse_locations` - Warehouse locations
|
||||
- `permissions` - Permission system
|
||||
- `role_permissions` - Role-based access
|
||||
- `role_hierarchy` - Role hierarchy
|
||||
- `permission_audit_log` - Audit logging
|
||||
- Plus SQLAlchemy tables: `users`, `roles`
|
||||
|
||||
### Initial Data
|
||||
- Superadmin user: `superadmin` / `superadmin123`
|
||||
|
||||
### Application Features
|
||||
- Complete Flask web application
|
||||
- Gunicorn WSGI server (4-8 workers depending on CPU)
|
||||
- Static file serving
|
||||
- Session management
|
||||
- Database connection pooling
|
||||
|
||||
## 🔄 Migration from Existing Deployment
|
||||
|
||||
If you have an existing non-Docker deployment:
|
||||
|
||||
### 1. Backup Current Data
|
||||
```bash
|
||||
# Backup database
|
||||
mysqldump -u trasabilitate -p trasabilitate > backup.sql
|
||||
|
||||
# Backup any uploaded files or custom data
|
||||
cp -r py_app/instance backup_instance/
|
||||
```
|
||||
|
||||
### 2. Deploy Docker Solution
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### 3. Restore Data (if needed)
|
||||
```bash
|
||||
# Restore database
|
||||
docker compose exec -T db mariadb -u trasabilitate -pInitial01! trasabilitate < backup.sql
|
||||
```
|
||||
|
||||
### 4. Stop Old Service
|
||||
```bash
|
||||
# Stop systemd service
|
||||
sudo systemctl stop trasabilitate
|
||||
sudo systemctl disable trasabilitate
|
||||
```
|
||||
|
||||
## 🎓 Learning Resources
|
||||
|
||||
- Docker Compose docs: https://docs.docker.com/compose/
|
||||
- Gunicorn configuration: https://docs.gunicorn.org/
|
||||
- MariaDB Docker: https://hub.docker.com/_/mariadb
|
||||
|
||||
## ✅ Testing Checklist
|
||||
|
||||
After deployment, verify:
|
||||
|
||||
- [ ] Services are running: `docker compose ps`
|
||||
- [ ] App is accessible: http://localhost:8781
|
||||
- [ ] Can log in with superadmin
|
||||
- [ ] Database contains tables: `make shell-db` then `SHOW TABLES;`
|
||||
- [ ] Logs are being written: `ls -la logs/`
|
||||
- [ ] Can restart services: `docker compose restart`
|
||||
- [ ] Data persists after restart
|
||||
|
||||
## 🆘 Support Commands
|
||||
|
||||
```bash
|
||||
# View all services
|
||||
docker compose ps
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Restart a specific service
|
||||
docker compose restart web
|
||||
|
||||
# Access web container shell
|
||||
docker compose exec web bash
|
||||
|
||||
# Access database
|
||||
docker compose exec db mariadb -u trasabilitate -p
|
||||
|
||||
# Check resource usage
|
||||
docker stats
|
||||
|
||||
# Remove everything and start fresh
|
||||
docker compose down -v
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
## 📝 Next Steps
|
||||
|
||||
1. **Install Docker** on the target server (if not already installed)
|
||||
2. **Review and customize** `.env` file after copying from `.env.example`
|
||||
3. **Run deployment**: `./deploy.sh`
|
||||
4. **Change default passwords** after first login
|
||||
5. **Set up reverse proxy** (nginx/traefik) for HTTPS if needed
|
||||
6. **Configure backups** using `make backup-db`
|
||||
7. **Monitor logs** regularly with `make logs`
|
||||
|
||||
## 🎉 Benefits of This Solution
|
||||
|
||||
1. **Portable**: Works on any system with Docker
|
||||
2. **Reproducible**: Same deployment every time
|
||||
3. **Isolated**: No conflicts with system packages
|
||||
4. **Easy Updates**: Just rebuild and restart
|
||||
5. **Scalable**: Can easily add more services
|
||||
6. **Professional**: Production-ready configuration
|
||||
7. **Documented**: Complete documentation included
|
||||
8. **Maintainable**: Simple management commands
|
||||
|
||||
---
|
||||
|
||||
**Your Flask application is now ready for modern, containerized deployment! 🚀**
|
||||
@@ -1,280 +0,0 @@
|
||||
# ✅ Docker Solution - Files Created
|
||||
|
||||
## 📦 Complete Docker Deployment Package
|
||||
|
||||
Your Flask application has been packaged into a complete Docker solution. Here's everything that was created:
|
||||
|
||||
### Core Docker Files
|
||||
|
||||
```
|
||||
/srv/quality_recticel/
|
||||
├── Dockerfile # Flask app container definition
|
||||
├── docker-compose.yml # Multi-container orchestration
|
||||
├── docker-entrypoint.sh # Container initialization script
|
||||
├── init-db.sql # MariaDB initialization
|
||||
├── .dockerignore # Build optimization
|
||||
└── .env.example # Configuration template
|
||||
```
|
||||
|
||||
### Deployment & Management
|
||||
|
||||
```
|
||||
├── deploy.sh # One-command deployment script
|
||||
├── Makefile # Management commands (make up, make down, etc.)
|
||||
├── README-DOCKER.md # Quick start guide
|
||||
├── DOCKER_DEPLOYMENT.md # Complete deployment documentation
|
||||
└── DOCKER_SOLUTION_SUMMARY.md # This comprehensive summary
|
||||
```
|
||||
|
||||
### Modified Files
|
||||
|
||||
```
|
||||
py_app/app/db_create_scripts/
|
||||
└── setup_complete_database.py # Updated to support Docker env vars
|
||||
```
|
||||
|
||||
## 🎯 What This Deployment Includes
|
||||
|
||||
### Services
|
||||
1. **Flask Web Application**
|
||||
- Python 3.10
|
||||
- Gunicorn WSGI server (production-ready)
|
||||
- Auto-generated database configuration
|
||||
- Health checks
|
||||
- Automatic restart on failure
|
||||
|
||||
2. **MariaDB 11.3 Database**
|
||||
- Automatic initialization
|
||||
- User and database creation
|
||||
- Data persistence (Docker volume)
|
||||
- Health checks
|
||||
|
||||
### Features
|
||||
- ✅ Single-command deployment
|
||||
- ✅ Automatic database schema setup
|
||||
- ✅ Superadmin user seeding
|
||||
- ✅ Data persistence across restarts
|
||||
- ✅ Container health monitoring
|
||||
- ✅ Log collection and management
|
||||
- ✅ Production-ready configuration
|
||||
- ✅ Easy backup and restore
|
||||
- ✅ Complete isolation from host system
|
||||
|
||||
## 🚀 How to Deploy
|
||||
|
||||
### Prerequisites
|
||||
**Install Docker first:**
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker $USER
|
||||
# Log out and back in
|
||||
```
|
||||
|
||||
### Deploy
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
That's it! Your application will be available at http://localhost:8781
|
||||
|
||||
## 📋 Usage Examples
|
||||
|
||||
### Basic Operations
|
||||
```bash
|
||||
# Start services
|
||||
docker compose up -d
|
||||
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Stop services
|
||||
docker compose down
|
||||
|
||||
# Restart
|
||||
docker compose restart
|
||||
|
||||
# Check status
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### Using Makefile (Recommended)
|
||||
```bash
|
||||
make install # First-time setup
|
||||
make up # Start services
|
||||
make down # Stop services
|
||||
make logs # View logs
|
||||
make logs-web # View only web logs
|
||||
make logs-db # View only database logs
|
||||
make shell # Access app container
|
||||
make shell-db # Access database console
|
||||
make backup-db # Backup database
|
||||
make status # Show service status
|
||||
make help # Show all commands
|
||||
```
|
||||
|
||||
### Advanced Operations
|
||||
```bash
|
||||
# Rebuild after code changes
|
||||
docker compose up -d --build web
|
||||
|
||||
# Access application shell
|
||||
docker compose exec web bash
|
||||
|
||||
# Run database commands
|
||||
docker compose exec db mariadb -u trasabilitate -p trasabilitate
|
||||
|
||||
# View resource usage
|
||||
docker stats recticel-app recticel-db
|
||||
|
||||
# Complete reset (removes all data!)
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
## 🗂️ Data Storage
|
||||
|
||||
### Persistent Data
|
||||
- **Database**: Stored in Docker volume `mariadb_data`
|
||||
- **Logs**: Mounted to `./logs` directory
|
||||
- **Config**: Mounted to `./instance` directory
|
||||
|
||||
### Backup Database
|
||||
```bash
|
||||
docker compose exec -T db mariadb-dump -u trasabilitate -pInitial01! trasabilitate > backup.sql
|
||||
```
|
||||
|
||||
### Restore Database
|
||||
```bash
|
||||
docker compose exec -T db mariadb -u trasabilitate -pInitial01! trasabilitate < backup.sql
|
||||
```
|
||||
|
||||
## 🔐 Default Credentials
|
||||
|
||||
### Application
|
||||
- URL: http://localhost:8781
|
||||
- Username: `superadmin`
|
||||
- Password: `superadmin123`
|
||||
- **⚠️ Change after first login!**
|
||||
|
||||
### Database
|
||||
- Host: `localhost:3306` (from host) or `db:3306` (from containers)
|
||||
- Database: `trasabilitate`
|
||||
- User: `trasabilitate`
|
||||
- Password: `Initial01!`
|
||||
- Root Password: Set in `.env` file
|
||||
|
||||
## 📊 Service Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ recticel-network (Docker) │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ recticel-db │ │ recticel-app │ │
|
||||
│ │ (MariaDB 11.3) │◄───────┤ (Flask/Python) │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ - Internal DB │ │ - Gunicorn │ │
|
||||
│ │ - Health Check │ │ - Health Check │ │
|
||||
│ │ - Auto Init │ │ - Auto Config │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ │
|
||||
│ │ │ │
|
||||
│ │ 3306 (optional) 8781 │ │
|
||||
└────────────┼──────────────────────────┼────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
[mariadb_data] [Host: 8781]
|
||||
Docker Volume Application Access
|
||||
```
|
||||
|
||||
## 🎓 Quick Reference
|
||||
|
||||
### Environment Variables (.env)
|
||||
```env
|
||||
MYSQL_ROOT_PASSWORD=rootpassword # MariaDB root password
|
||||
DB_PORT=3306 # Database port (external)
|
||||
APP_PORT=8781 # Application port
|
||||
INIT_DB=true # Run DB initialization
|
||||
SEED_DB=true # Seed superadmin user
|
||||
```
|
||||
|
||||
### Important Ports
|
||||
- `8781`: Flask application (web interface)
|
||||
- `3306`: MariaDB database (optional external access)
|
||||
|
||||
### Log Locations
|
||||
- Application logs: `./logs/access.log` and `./logs/error.log`
|
||||
- Container logs: `docker compose logs`
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Can't connect to application
|
||||
```bash
|
||||
# Check if services are running
|
||||
docker compose ps
|
||||
|
||||
# Check web logs
|
||||
docker compose logs web
|
||||
|
||||
# Verify port not in use
|
||||
netstat -tuln | grep 8781
|
||||
```
|
||||
|
||||
### Database connection issues
|
||||
```bash
|
||||
# Check database health
|
||||
docker compose exec db healthcheck.sh --connect
|
||||
|
||||
# View database logs
|
||||
docker compose logs db
|
||||
|
||||
# Test database connection
|
||||
docker compose exec web python3 -c "import mariadb; print('OK')"
|
||||
```
|
||||
|
||||
### Port already in use
|
||||
Edit `.env` file:
|
||||
```env
|
||||
APP_PORT=8782 # Change to available port
|
||||
DB_PORT=3307 # Change if needed
|
||||
```
|
||||
|
||||
### Start completely fresh
|
||||
```bash
|
||||
docker compose down -v
|
||||
rm -rf logs/* instance/external_server.conf
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
## 📖 Documentation Files
|
||||
|
||||
1. **README-DOCKER.md** - Quick start guide (start here!)
|
||||
2. **DOCKER_DEPLOYMENT.md** - Complete deployment guide
|
||||
3. **DOCKER_SOLUTION_SUMMARY.md** - Comprehensive overview
|
||||
4. **FILES_CREATED.md** - This file
|
||||
|
||||
## ✨ Benefits
|
||||
|
||||
- **No System Dependencies**: Only Docker required
|
||||
- **Portable**: Deploy on any system with Docker
|
||||
- **Reproducible**: Consistent deployments every time
|
||||
- **Isolated**: No conflicts with other applications
|
||||
- **Production-Ready**: Gunicorn, health checks, proper logging
|
||||
- **Easy Management**: Simple commands, one-line deployment
|
||||
- **Persistent**: Data survives container restarts
|
||||
- **Scalable**: Easy to add more services
|
||||
|
||||
## 🎉 Success!
|
||||
|
||||
Your Recticel Quality Application is now containerized and ready for deployment!
|
||||
|
||||
**Next Steps:**
|
||||
1. Install Docker (if not already installed)
|
||||
2. Run `./deploy.sh`
|
||||
3. Access http://localhost:8781
|
||||
4. Log in with superadmin credentials
|
||||
5. Change default passwords
|
||||
6. Enjoy your containerized application!
|
||||
|
||||
For detailed instructions, see **README-DOCKER.md** or **DOCKER_DEPLOYMENT.md**.
|
||||
@@ -1,73 +0,0 @@
|
||||
# 🚀 Quick Start - Docker Deployment
|
||||
|
||||
## What You Need
|
||||
- A server with Docker installed
|
||||
- 2GB free disk space
|
||||
- Ports 8781 and 3306 available
|
||||
|
||||
## Deploy in 3 Steps
|
||||
|
||||
### 1️⃣ Install Docker (if not already installed)
|
||||
|
||||
**Ubuntu/Debian:**
|
||||
```bash
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
Then log out and back in.
|
||||
|
||||
### 2️⃣ Deploy the Application
|
||||
```bash
|
||||
cd /srv/quality_recticel
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### 3️⃣ Access Your Application
|
||||
Open browser: **http://localhost:8781**
|
||||
|
||||
**Login:**
|
||||
- Username: `superadmin`
|
||||
- Password: `superadmin123`
|
||||
|
||||
## 🎯 Done!
|
||||
|
||||
Your complete application with database is now running in Docker containers.
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Stop services
|
||||
docker compose down
|
||||
|
||||
# Restart services
|
||||
docker compose restart
|
||||
|
||||
# Backup database
|
||||
docker compose exec -T db mariadb-dump -u trasabilitate -pInitial01! trasabilitate > backup.sql
|
||||
```
|
||||
|
||||
## 📚 Full Documentation
|
||||
|
||||
See `DOCKER_DEPLOYMENT.md` for complete documentation.
|
||||
|
||||
## 🆘 Problems?
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
docker compose ps
|
||||
|
||||
# View detailed logs
|
||||
docker compose logs -f web
|
||||
|
||||
# Start fresh
|
||||
docker compose down -v
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Note:** This is a production-ready deployment using Gunicorn WSGI server, MariaDB 11.3, and proper health checks.
|
||||
@@ -1,121 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to add modules column to external database and migrate existing users
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import mariadb
|
||||
|
||||
def migrate_external_database():
|
||||
"""Add modules column to external database and update existing users"""
|
||||
try:
|
||||
# Read external database configuration from instance folder
|
||||
config_file = os.path.join(os.path.dirname(__file__), 'instance/external_server.conf')
|
||||
if not os.path.exists(config_file):
|
||||
print("External database configuration file not found at instance/external_server.conf")
|
||||
return False
|
||||
|
||||
with open(config_file, 'r') as f:
|
||||
lines = f.read().strip().split('\n')
|
||||
|
||||
# Parse the config file format "key=value"
|
||||
config = {}
|
||||
for line in lines:
|
||||
if '=' in line and not line.strip().startswith('#'):
|
||||
key, value = line.split('=', 1)
|
||||
config[key.strip()] = value.strip()
|
||||
|
||||
host = config.get('server_domain', 'localhost')
|
||||
port = int(config.get('port', '3306'))
|
||||
database = config.get('database_name', '')
|
||||
user = config.get('username', '')
|
||||
password = config.get('password', '')
|
||||
|
||||
if not all([host, database, user, password]):
|
||||
print("Missing required database configuration values.")
|
||||
return False
|
||||
|
||||
print(f"Connecting to external database: {host}:{port}/{database}")
|
||||
|
||||
# Connect to external database
|
||||
conn = mariadb.connect(
|
||||
user=user,
|
||||
password=password,
|
||||
host=host,
|
||||
port=port,
|
||||
database=database
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if users table exists
|
||||
cursor.execute("SHOW TABLES LIKE 'users'")
|
||||
if not cursor.fetchone():
|
||||
print("Users table not found in external database.")
|
||||
conn.close()
|
||||
return False
|
||||
|
||||
# Check if modules column already exists
|
||||
cursor.execute("DESCRIBE users")
|
||||
columns = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
if 'modules' not in columns:
|
||||
print("Adding modules column to users table...")
|
||||
cursor.execute("ALTER TABLE users ADD COLUMN modules TEXT")
|
||||
print("Modules column added successfully.")
|
||||
else:
|
||||
print("Modules column already exists.")
|
||||
|
||||
# Get current users and convert their roles
|
||||
cursor.execute("SELECT id, username, role FROM users")
|
||||
users = cursor.fetchall()
|
||||
|
||||
role_mapping = {
|
||||
'superadmin': ('superadmin', None),
|
||||
'administrator': ('admin', None),
|
||||
'admin': ('admin', None),
|
||||
'quality': ('manager', '["quality"]'),
|
||||
'warehouse': ('manager', '["warehouse"]'),
|
||||
'warehouse_manager': ('manager', '["warehouse"]'),
|
||||
'scan': ('worker', '["quality"]'),
|
||||
'etichete': ('manager', '["labels"]'),
|
||||
'quality_manager': ('manager', '["quality"]'),
|
||||
'quality_worker': ('worker', '["quality"]'),
|
||||
}
|
||||
|
||||
print(f"Migrating {len(users)} users...")
|
||||
|
||||
for user_id, username, old_role in users:
|
||||
if old_role in role_mapping:
|
||||
new_role, modules_json = role_mapping[old_role]
|
||||
|
||||
cursor.execute("UPDATE users SET role = ?, modules = ? WHERE id = ?",
|
||||
(new_role, modules_json, user_id))
|
||||
|
||||
print(f" {username}: {old_role} -> {new_role} with modules {modules_json}")
|
||||
else:
|
||||
print(f" {username}: Unknown role '{old_role}', keeping as-is")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print("External database migration completed successfully!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error migrating external database: {e}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("External Database Migration for Simplified 4-Tier Permission System")
|
||||
print("=" * 70)
|
||||
|
||||
success = migrate_external_database()
|
||||
|
||||
if success:
|
||||
print("\n✅ Migration completed successfully!")
|
||||
print("\nUsers can now log in with the new simplified permission system.")
|
||||
print("Role structure: superadmin → admin → manager → worker")
|
||||
print("Modules: quality, warehouse, labels")
|
||||
else:
|
||||
print("\n❌ Migration failed. Please check the error messages above.")
|
||||
@@ -1,172 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Migration script to convert from complex permission system to simplified 4-tier system
|
||||
This script will:
|
||||
1. Add 'modules' column to users table
|
||||
2. Convert existing roles to new 4-tier system
|
||||
3. Assign appropriate modules based on old roles
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Add the app directory to Python path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
def get_db_connections():
|
||||
"""Get both internal SQLite and external database connections"""
|
||||
connections = {}
|
||||
|
||||
# Internal SQLite database
|
||||
internal_db_path = os.path.join(os.path.dirname(__file__), 'instance/users.db')
|
||||
if os.path.exists(internal_db_path):
|
||||
connections['internal'] = sqlite3.connect(internal_db_path)
|
||||
print(f"Connected to internal SQLite database: {internal_db_path}")
|
||||
|
||||
# External database (try to connect using existing method)
|
||||
try:
|
||||
import mariadb
|
||||
|
||||
# Read external database configuration
|
||||
config_file = os.path.join(os.path.dirname(__file__), '../external_database_settings')
|
||||
if os.path.exists(config_file):
|
||||
with open(config_file, 'r') as f:
|
||||
lines = f.read().strip().split('\n')
|
||||
if len(lines) >= 5:
|
||||
host = lines[0].strip()
|
||||
port = int(lines[1].strip())
|
||||
database = lines[2].strip()
|
||||
user = lines[3].strip()
|
||||
password = lines[4].strip()
|
||||
|
||||
conn = mariadb.connect(
|
||||
user=user,
|
||||
password=password,
|
||||
host=host,
|
||||
port=port,
|
||||
database=database
|
||||
)
|
||||
connections['external'] = conn
|
||||
print(f"Connected to external MariaDB database: {host}:{port}/{database}")
|
||||
except Exception as e:
|
||||
print(f"Could not connect to external database: {e}")
|
||||
|
||||
return connections
|
||||
|
||||
def role_mapping():
|
||||
"""Map old roles to new 4-tier system"""
|
||||
return {
|
||||
# Old role -> (new_role, modules)
|
||||
'superadmin': ('superadmin', []), # All modules by default
|
||||
'administrator': ('admin', []), # All modules by default
|
||||
'admin': ('admin', []), # All modules by default
|
||||
'quality': ('manager', ['quality']),
|
||||
'warehouse': ('manager', ['warehouse']),
|
||||
'warehouse_manager': ('manager', ['warehouse']),
|
||||
'scan': ('worker', ['quality']), # Assume scan users are quality workers
|
||||
'etichete': ('manager', ['labels']),
|
||||
'quality_manager': ('manager', ['quality']),
|
||||
'quality_worker': ('worker', ['quality']),
|
||||
}
|
||||
|
||||
def migrate_database(conn, db_type):
|
||||
"""Migrate a specific database"""
|
||||
cursor = conn.cursor()
|
||||
|
||||
print(f"Migrating {db_type} database...")
|
||||
|
||||
# Check if users table exists
|
||||
if db_type == 'internal':
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'")
|
||||
else: # external/MariaDB
|
||||
cursor.execute("SHOW TABLES LIKE 'users'")
|
||||
|
||||
if not cursor.fetchone():
|
||||
print(f"No users table found in {db_type} database")
|
||||
return
|
||||
|
||||
# Check if modules column already exists
|
||||
try:
|
||||
if db_type == 'internal':
|
||||
cursor.execute("PRAGMA table_info(users)")
|
||||
columns = [row[1] for row in cursor.fetchall()]
|
||||
else: # external/MariaDB
|
||||
cursor.execute("DESCRIBE users")
|
||||
columns = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
if 'modules' not in columns:
|
||||
print(f"Adding modules column to {db_type} database...")
|
||||
if db_type == 'internal':
|
||||
cursor.execute("ALTER TABLE users ADD COLUMN modules TEXT")
|
||||
else: # external/MariaDB
|
||||
cursor.execute("ALTER TABLE users ADD COLUMN modules TEXT")
|
||||
else:
|
||||
print(f"Modules column already exists in {db_type} database")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error checking/adding modules column in {db_type}: {e}")
|
||||
return
|
||||
|
||||
# Get current users
|
||||
cursor.execute("SELECT id, username, role FROM users")
|
||||
users = cursor.fetchall()
|
||||
|
||||
print(f"Found {len(users)} users in {db_type} database")
|
||||
|
||||
# Convert roles and assign modules
|
||||
mapping = role_mapping()
|
||||
updates = []
|
||||
|
||||
for user_id, username, old_role in users:
|
||||
if old_role in mapping:
|
||||
new_role, modules = mapping[old_role]
|
||||
modules_json = json.dumps(modules) if modules else None
|
||||
updates.append((new_role, modules_json, user_id, username))
|
||||
print(f" {username}: {old_role} -> {new_role} with modules {modules}")
|
||||
else:
|
||||
print(f" {username}: Unknown role '{old_role}', keeping as-is")
|
||||
|
||||
# Apply updates
|
||||
for new_role, modules_json, user_id, username in updates:
|
||||
try:
|
||||
cursor.execute("UPDATE users SET role = ?, modules = ? WHERE id = ?",
|
||||
(new_role, modules_json, user_id))
|
||||
print(f" Updated {username} successfully")
|
||||
except Exception as e:
|
||||
print(f" Error updating {username}: {e}")
|
||||
|
||||
conn.commit()
|
||||
print(f"Migration completed for {db_type} database")
|
||||
|
||||
def main():
|
||||
"""Main migration function"""
|
||||
print("Starting migration to simplified 4-tier permission system...")
|
||||
print("="*60)
|
||||
|
||||
connections = get_db_connections()
|
||||
|
||||
if not connections:
|
||||
print("No database connections available. Please check your configuration.")
|
||||
return
|
||||
|
||||
for db_type, conn in connections.items():
|
||||
try:
|
||||
migrate_database(conn, db_type)
|
||||
print()
|
||||
except Exception as e:
|
||||
print(f"Error migrating {db_type} database: {e}")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
print("Migration completed!")
|
||||
print("\nNew role structure:")
|
||||
print("- superadmin: Full system access")
|
||||
print("- admin: Full app access (except role_permissions and download_extension)")
|
||||
print("- manager: Module-based access (can have multiple modules)")
|
||||
print("- worker: Limited module access (one module only)")
|
||||
print("\nAvailable modules: quality, warehouse, labels")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,111 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for the new simplified 4-tier permission system
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
|
||||
|
||||
from permissions_simple import check_access, validate_user_modules, get_user_accessible_pages
|
||||
|
||||
def test_permission_system():
|
||||
"""Test the new permission system with various scenarios"""
|
||||
print("Testing Simplified 4-Tier Permission System")
|
||||
print("=" * 50)
|
||||
|
||||
# Test cases: (role, modules, page, expected_result)
|
||||
test_cases = [
|
||||
# Superadmin tests
|
||||
('superadmin', [], 'dashboard', True),
|
||||
('superadmin', [], 'role_permissions', True),
|
||||
('superadmin', [], 'quality', True),
|
||||
('superadmin', [], 'warehouse', True),
|
||||
|
||||
# Admin tests
|
||||
('admin', [], 'dashboard', True),
|
||||
('admin', [], 'role_permissions', False), # Restricted for admin
|
||||
('admin', [], 'download_extension', False), # Restricted for admin
|
||||
('admin', [], 'quality', True),
|
||||
('admin', [], 'warehouse', True),
|
||||
|
||||
# Manager tests
|
||||
('manager', ['quality'], 'quality', True),
|
||||
('manager', ['quality'], 'quality_reports', True),
|
||||
('manager', ['quality'], 'warehouse', False), # No warehouse module
|
||||
('manager', ['warehouse'], 'warehouse', True),
|
||||
('manager', ['warehouse'], 'quality', False), # No quality module
|
||||
('manager', ['quality', 'warehouse'], 'quality', True), # Multiple modules
|
||||
('manager', ['quality', 'warehouse'], 'warehouse', True),
|
||||
|
||||
# Worker tests
|
||||
('worker', ['quality'], 'quality', True),
|
||||
('worker', ['quality'], 'quality_reports', False), # Workers can't access reports
|
||||
('worker', ['quality'], 'warehouse', False), # No warehouse module
|
||||
('worker', ['warehouse'], 'move_orders', True),
|
||||
('worker', ['warehouse'], 'create_locations', False), # Workers can't create locations
|
||||
|
||||
# Invalid role test
|
||||
('invalid_role', ['quality'], 'quality', False),
|
||||
]
|
||||
|
||||
print("Testing access control:")
|
||||
print("-" * 30)
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for role, modules, page, expected in test_cases:
|
||||
result = check_access(role, modules, page)
|
||||
status = "PASS" if result == expected else "FAIL"
|
||||
print(f"{status}: {role:12} {str(modules):20} {page:18} -> {result} (expected {expected})")
|
||||
|
||||
if result == expected:
|
||||
passed += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
print(f"\nResults: {passed} passed, {failed} failed")
|
||||
|
||||
# Test module validation
|
||||
print("\nTesting module validation:")
|
||||
print("-" * 30)
|
||||
|
||||
validation_tests = [
|
||||
('superadmin', ['quality'], True), # Superadmin can have any modules
|
||||
('admin', ['warehouse'], True), # Admin can have any modules
|
||||
('manager', ['quality'], True), # Manager can have one module
|
||||
('manager', ['quality', 'warehouse'], True), # Manager can have multiple modules
|
||||
('manager', [], False), # Manager must have at least one module
|
||||
('worker', ['quality'], True), # Worker can have one module
|
||||
('worker', ['quality', 'warehouse'], False), # Worker cannot have multiple modules
|
||||
('worker', [], False), # Worker must have exactly one module
|
||||
('invalid_role', ['quality'], False), # Invalid role
|
||||
]
|
||||
|
||||
for role, modules, expected in validation_tests:
|
||||
is_valid, error_msg = validate_user_modules(role, modules)
|
||||
status = "PASS" if is_valid == expected else "FAIL"
|
||||
print(f"{status}: {role:12} {str(modules):20} -> {is_valid} (expected {expected})")
|
||||
if error_msg:
|
||||
print(f" Error: {error_msg}")
|
||||
|
||||
# Test accessible pages for different users
|
||||
print("\nTesting accessible pages:")
|
||||
print("-" * 30)
|
||||
|
||||
user_tests = [
|
||||
('superadmin', []),
|
||||
('admin', []),
|
||||
('manager', ['quality']),
|
||||
('manager', ['warehouse']),
|
||||
('worker', ['quality']),
|
||||
('worker', ['warehouse']),
|
||||
]
|
||||
|
||||
for role, modules in user_tests:
|
||||
accessible_pages = get_user_accessible_pages(role, modules)
|
||||
print(f"{role:12} {str(modules):20} -> {len(accessible_pages)} pages: {', '.join(accessible_pages[:5])}{'...' if len(accessible_pages) > 5 else ''}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_permission_system()
|
||||
263
py_app/ENHANCED_PRINT_CONTROLLER.md
Executable file
@@ -0,0 +1,263 @@
|
||||
# Enhanced Print Controller - Features & Usage
|
||||
|
||||
## Overview
|
||||
The print module now includes an advanced Print Controller with real-time monitoring, error detection, pause/resume functionality, and automatic reprint capabilities for handling printer issues like paper jams or running out of paper.
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. **Real-Time Progress Modal**
|
||||
- Visual progress bar showing percentage completion
|
||||
- Live counter showing "X / Y" labels printed
|
||||
- Status messages updating in real-time
|
||||
- Detailed event log with timestamps
|
||||
|
||||
### 2. **Print Status Log**
|
||||
- Timestamped entries for all print events
|
||||
- Color-coded status messages:
|
||||
- **Green**: Successful operations
|
||||
- **Yellow**: Warnings and paused states
|
||||
- **Red**: Errors and failures
|
||||
- Auto-scrolling to show latest events
|
||||
- Scrollable history of all print activities
|
||||
|
||||
### 3. **Control Buttons**
|
||||
|
||||
#### **⏸️ Pause Button**
|
||||
- Pauses printing between labels
|
||||
- Useful for:
|
||||
- Checking printer paper level
|
||||
- Inspecting print quality
|
||||
- Loading more paper
|
||||
- Progress bar turns yellow when paused
|
||||
|
||||
#### **▶️ Resume Button**
|
||||
- Resumes printing from where it was paused
|
||||
- Appears when print job is paused
|
||||
- Progress bar returns to normal green
|
||||
|
||||
#### **🔄 Reprint Last Button**
|
||||
- Available after each successful print
|
||||
- Reprints the last completed label
|
||||
- Useful when:
|
||||
- Label came out damaged
|
||||
- Print quality was poor
|
||||
- Label fell on the floor
|
||||
|
||||
#### **❌ Cancel Button**
|
||||
- Stops the entire print job
|
||||
- Shows how many labels were completed
|
||||
- Progress bar turns red
|
||||
- Database not updated on cancellation
|
||||
|
||||
### 4. **Automatic Error Detection**
|
||||
- Detects when a label fails to print
|
||||
- Automatically pauses the job
|
||||
- Shows error message in log
|
||||
- Progress bar turns red
|
||||
- Prompts user to check printer
|
||||
|
||||
### 5. **Automatic Recovery**
|
||||
When a print error occurs:
|
||||
1. Job pauses automatically
|
||||
2. Error is logged with timestamp
|
||||
3. User checks and fixes printer issue (refill paper, clear jam)
|
||||
4. User clicks "Resume"
|
||||
5. Failed label is automatically retried
|
||||
6. If retry succeeds, continues with next label
|
||||
7. If retry fails, user can cancel or try again
|
||||
|
||||
### 6. **Smart Print Management**
|
||||
- Tracks current label being printed
|
||||
- Remembers last successfully printed label
|
||||
- Maintains list of failed labels
|
||||
- Prevents duplicate printing
|
||||
- Sequential label numbering (CP00000777/001, 002, 003...)
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
### Normal Printing Workflow
|
||||
|
||||
1. **Start Print Job**
|
||||
- Select an order from the table
|
||||
- Click "Print Label (QZ Tray)" button
|
||||
- Print Controller modal appears
|
||||
|
||||
2. **Monitor Progress**
|
||||
- Watch progress bar fill (green)
|
||||
- Check "X / Y" counter
|
||||
- Read status messages
|
||||
- View timestamped log entries
|
||||
|
||||
3. **Completion**
|
||||
- All labels print successfully
|
||||
- Database updates automatically
|
||||
- Table refreshes to show new status
|
||||
- Modal closes automatically
|
||||
- Success notification appears
|
||||
|
||||
### Handling Paper Running Out Mid-Print
|
||||
|
||||
**Scenario**: Printing 20 labels, paper runs out after label 12
|
||||
|
||||
1. **Detection**
|
||||
- Label 13 fails to print
|
||||
- Controller detects error
|
||||
- Job pauses automatically
|
||||
- Progress bar turns red
|
||||
- Log shows: "✗ Label 13 failed: Print error"
|
||||
- Status: "⚠️ ERROR - Check printer (paper jam/out of paper)"
|
||||
|
||||
2. **User Action**
|
||||
- Check printer
|
||||
- See paper is empty
|
||||
- Load new paper roll
|
||||
- Ensure paper is feeding correctly
|
||||
|
||||
3. **Resume Printing**
|
||||
- Click "▶️ Resume" button
|
||||
- Controller automatically retries label 13
|
||||
- Log shows: "Retrying label 13..."
|
||||
- If successful: "✓ Label 13 printed successfully (retry)"
|
||||
- Continues with labels 14-20
|
||||
- Job completes normally
|
||||
|
||||
### Handling Print Quality Issues
|
||||
|
||||
**Scenario**: Label 5 of 10 prints too light
|
||||
|
||||
1. **During Print**
|
||||
- Wait for label 5 to complete
|
||||
- "🔄 Reprint Last" button appears
|
||||
- Click button
|
||||
- Label 5 reprints with current settings
|
||||
|
||||
2. **Adjust & Continue**
|
||||
- Adjust printer darkness setting
|
||||
- Click "▶️ Resume" if paused
|
||||
- Continue printing labels 6-10
|
||||
|
||||
### Manual Pause for Inspection
|
||||
|
||||
**Scenario**: Want to check label quality mid-batch
|
||||
|
||||
1. Click "⏸️ Pause" button
|
||||
2. Progress bar turns yellow
|
||||
3. Remove and inspect last printed label
|
||||
4. If good: Click "▶️ Resume"
|
||||
5. If bad:
|
||||
- Click "🔄 Reprint Last"
|
||||
- Adjust printer settings
|
||||
- Click "▶️ Resume"
|
||||
|
||||
### Emergency Cancellation
|
||||
|
||||
**Scenario**: Wrong order selected or major printer malfunction
|
||||
|
||||
1. Click "❌ Cancel" button
|
||||
2. Printing stops immediately
|
||||
3. Log shows labels completed (e.g., "7 of 25")
|
||||
4. Progress bar turns red
|
||||
5. Modal stays open for 2 seconds
|
||||
6. Warning notification appears
|
||||
7. Database NOT updated
|
||||
8. Can reprint the order later
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### Print Controller State
|
||||
```javascript
|
||||
{
|
||||
isPaused: false, // Whether job is paused
|
||||
isCancelled: false, // Whether job is cancelled
|
||||
currentLabel: 0, // Current label number being printed
|
||||
totalLabels: 0, // Total labels in job
|
||||
lastPrintedLabel: 0, // Last successfully printed label
|
||||
failedLabels: [], // Array of failed label numbers
|
||||
orderData: null, // Order information
|
||||
printerName: null // Selected printer name
|
||||
}
|
||||
```
|
||||
|
||||
### Event Log Format
|
||||
```
|
||||
[17:47:15] Starting print job: 10 labels
|
||||
[17:47:15] Printer: Thermal Printer A
|
||||
[17:47:15] Order: CP00000777
|
||||
[17:47:16] Sending label 1 to printer...
|
||||
[17:47:16] ✓ Label 1 printed successfully
|
||||
```
|
||||
|
||||
### Error Detection
|
||||
- Try/catch around each print operation
|
||||
- Errors trigger automatic pause
|
||||
- Failed label number recorded
|
||||
- Automatic retry on resume
|
||||
|
||||
### Progress Calculation
|
||||
```javascript
|
||||
percentage = (currentLabel / totalLabels) * 100
|
||||
```
|
||||
|
||||
### Color States
|
||||
- **Green**: Normal printing
|
||||
- **Yellow**: Paused (manual or automatic)
|
||||
- **Red**: Error or cancelled
|
||||
|
||||
## Benefits
|
||||
|
||||
1. ✅ **Prevents Wasted Labels**: Automatic recovery from errors
|
||||
2. ✅ **Reduces Operator Stress**: Clear status and easy controls
|
||||
3. ✅ **Handles Paper Depletion**: Auto-pause and retry on paper out
|
||||
4. ✅ **Quality Control**: Easy reprint of damaged labels
|
||||
5. ✅ **Transparency**: Full log of all print activities
|
||||
6. ✅ **Flexibility**: Pause anytime for inspection
|
||||
7. ✅ **Safety**: Cancel button for emergencies
|
||||
8. ✅ **Accuracy**: Sequential numbering maintained even with errors
|
||||
|
||||
## Common Scenarios Handled
|
||||
|
||||
| Issue | Detection | Solution |
|
||||
|-------|-----------|----------|
|
||||
| Paper runs out | Print error on next label | Auto-pause, user refills, resume |
|
||||
| Paper jam | Print error detected | Auto-pause, user clears jam, resume |
|
||||
| Poor print quality | Visual inspection | Reprint last label |
|
||||
| Wrong order selected | User realizes mid-print | Cancel job |
|
||||
| Need to inspect labels | User decision | Pause, inspect, resume |
|
||||
| Label falls on floor | Visual observation | Reprint last label |
|
||||
| Printer offline | Print error | Auto-pause, user fixes, resume |
|
||||
|
||||
## Future Enhancements (Possible)
|
||||
|
||||
- Printer status monitoring (paper level, online/offline)
|
||||
- Print queue for multiple orders
|
||||
- Estimated time remaining
|
||||
- Sound notifications on completion
|
||||
- Email/SMS alerts for long jobs
|
||||
- Print history logging to database
|
||||
- Batch printing multiple orders
|
||||
- Automatic printer reconnection
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
1. **Normal Job**: Print 5-10 labels, verify all complete
|
||||
2. **Paper Depletion**: Remove paper mid-job, verify auto-pause and recovery
|
||||
3. **Pause/Resume**: Manually pause mid-job, wait, resume
|
||||
4. **Reprint**: Print job, reprint last label multiple times
|
||||
5. **Cancel**: Start job, cancel after 2-3 labels
|
||||
6. **Error Recovery**: Simulate error, verify automatic retry
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
- Chrome/Edge: ✅ Fully supported
|
||||
- Firefox: ✅ Fully supported
|
||||
- Safari: ✅ Fully supported
|
||||
- Mobile browsers: ⚠️ Desktop recommended for QZ Tray
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check browser console for detailed error messages
|
||||
- Verify QZ Tray is running and connected
|
||||
- Check printer is online and has paper
|
||||
- Review print status log in modal
|
||||
- Restart QZ Tray if connection issues persist
|
||||
133
py_app/MOBILE_LOGIN_GUIDE.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Mobile-Responsive Login Page
|
||||
|
||||
## Overview
|
||||
The login page has been enhanced with comprehensive mobile-responsive CSS to provide an optimal user experience across all device types and screen sizes.
|
||||
|
||||
## Mobile-Responsive Features Added
|
||||
|
||||
### 1. **Responsive Breakpoints**
|
||||
- **Tablet (≤768px)**: Column layout, optimized logo and form sizing
|
||||
- **Mobile (≤480px)**: Enhanced touch targets, better spacing
|
||||
- **Small Mobile (≤320px)**: Minimal padding, compact design
|
||||
- **Landscape (height ≤500px)**: Horizontal layout for landscape phones
|
||||
|
||||
### 2. **Layout Adaptations**
|
||||
|
||||
#### Desktop (>768px)
|
||||
- Side-by-side logo and form layout
|
||||
- Large logo (90vh height)
|
||||
- Fixed form width (600px)
|
||||
|
||||
#### Tablet (≤768px)
|
||||
- Vertical stacked layout
|
||||
- Logo height reduced to 30vh
|
||||
- Form width becomes responsive (100%, max 400px)
|
||||
|
||||
#### Mobile (≤480px)
|
||||
- Optimized touch targets (44px minimum)
|
||||
- Increased padding and margins
|
||||
- Better visual hierarchy
|
||||
- Enhanced shadows and border radius
|
||||
|
||||
#### Small Mobile (≤320px)
|
||||
- Minimal padding to maximize space
|
||||
- Compact logo (20vh height)
|
||||
- Reduced font sizes where appropriate
|
||||
|
||||
### 3. **Touch Optimizations**
|
||||
|
||||
#### iOS/Safari Specific
|
||||
- `font-size: 16px` on inputs prevents automatic zoom
|
||||
- Proper touch target sizing (44px minimum)
|
||||
|
||||
#### Touch Device Enhancements
|
||||
- Active states for button presses
|
||||
- Optimized image rendering for high DPI screens
|
||||
- Hover effects disabled on touch devices
|
||||
|
||||
### 4. **Accessibility Improvements**
|
||||
- Proper contrast ratios maintained
|
||||
- Touch targets meet accessibility guidelines
|
||||
- Readable font sizes across all devices
|
||||
- Smooth transitions and animations
|
||||
|
||||
### 5. **Performance Considerations**
|
||||
- CSS-only responsive design (no JavaScript required)
|
||||
- Efficient media queries
|
||||
- Optimized image rendering for retina displays
|
||||
|
||||
## Key CSS Features
|
||||
|
||||
### Flexible Layout
|
||||
```css
|
||||
.login-page {
|
||||
display: flex;
|
||||
flex-direction: column; /* Mobile */
|
||||
justify-content: center;
|
||||
}
|
||||
```
|
||||
|
||||
### Responsive Images
|
||||
```css
|
||||
.login-logo {
|
||||
max-height: 25vh; /* Mobile */
|
||||
max-width: 85vw;
|
||||
}
|
||||
```
|
||||
|
||||
### Touch-Friendly Inputs
|
||||
```css
|
||||
.form-container input {
|
||||
padding: 12px;
|
||||
font-size: 16px; /* Prevents iOS zoom */
|
||||
min-height: 44px; /* Touch target size */
|
||||
}
|
||||
```
|
||||
|
||||
### Landscape Optimization
|
||||
```css
|
||||
@media screen and (max-height: 500px) and (orientation: landscape) {
|
||||
.login-page {
|
||||
flex-direction: row; /* Back to horizontal */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
### Device Testing
|
||||
- [ ] iPhone (various sizes)
|
||||
- [ ] Android phones (various sizes)
|
||||
- [ ] iPad/Android tablets
|
||||
- [ ] Desktop browsers with responsive mode
|
||||
|
||||
### Orientation Testing
|
||||
- [ ] Portrait mode on all devices
|
||||
- [ ] Landscape mode on phones
|
||||
- [ ] Landscape mode on tablets
|
||||
|
||||
### Browser Testing
|
||||
- [ ] Safari (iOS)
|
||||
- [ ] Chrome (Android/iOS)
|
||||
- [ ] Firefox Mobile
|
||||
- [ ] Samsung Internet
|
||||
- [ ] Desktop browsers (Chrome, Firefox, Safari, Edge)
|
||||
|
||||
## Browser Support
|
||||
- Modern browsers (ES6+ support)
|
||||
- iOS Safari 12+
|
||||
- Android Chrome 70+
|
||||
- Desktop browsers (last 2 versions)
|
||||
|
||||
## Performance Impact
|
||||
- **CSS Size**: Increased by ~2KB (compressed)
|
||||
- **Load Time**: No impact (CSS only)
|
||||
- **Rendering**: Optimized for mobile GPUs
|
||||
- **Memory**: Minimal additional usage
|
||||
|
||||
## Future Enhancements
|
||||
1. **Dark mode mobile optimizations**
|
||||
2. **Progressive Web App (PWA) features**
|
||||
3. **Biometric authentication UI**
|
||||
4. **Loading states and animations**
|
||||
5. **Error message responsive design**
|
||||
125
py_app/PRINT_PROGRESS_FEATURE.md
Executable file
@@ -0,0 +1,125 @@
|
||||
# Print Progress Modal Feature
|
||||
|
||||
## Overview
|
||||
Added a visual progress modal that displays during label printing operations via QZ Tray. The modal shows real-time progress, updates the database upon completion, and refreshes the table view automatically.
|
||||
|
||||
## Features Implemented
|
||||
|
||||
### 1. Progress Modal UI
|
||||
- **Modal Overlay**: Full-screen semi-transparent overlay to focus user attention
|
||||
- **Progress Bar**: Animated progress bar showing percentage completion
|
||||
- **Status Messages**: Real-time status updates during printing
|
||||
- **Label Counter**: Shows "X / Y" format for current progress (e.g., "5 / 10")
|
||||
|
||||
### 2. Print Flow Improvements
|
||||
The printing process now follows these steps:
|
||||
|
||||
1. **Validation**: Check QZ Tray connection and printer selection
|
||||
2. **Modal Display**: Show progress modal immediately
|
||||
3. **Sequential Printing**: Print each label one by one with progress updates
|
||||
- Update progress bar after each successful print
|
||||
- Show current label number being printed
|
||||
- 500ms delay between labels for printer processing
|
||||
4. **Database Update**: Call `/update_printed_status/<order_id>` endpoint
|
||||
- Marks the order as printed in the database
|
||||
- Handles errors gracefully (prints still succeed even if DB update fails)
|
||||
5. **Table Refresh**: Automatically click "Load Orders" button to refresh the view
|
||||
6. **Modal Close**: Hide modal after completion
|
||||
7. **Notification**: Show success notification to user
|
||||
|
||||
### 3. Progress Updates
|
||||
The modal displays different status messages:
|
||||
- "Preparing to print..." (initial)
|
||||
- "Printing label X of Y..." (during printing)
|
||||
- "✅ All labels printed! Updating database..." (after prints complete)
|
||||
- "✅ Complete! Refreshing table..." (after DB update)
|
||||
- "⚠️ Labels printed but database update failed" (on DB error)
|
||||
|
||||
### 4. Error Handling
|
||||
- Modal automatically closes on any error
|
||||
- Error notifications shown to user
|
||||
- Database update failures don't prevent successful printing
|
||||
- Graceful degradation if DB update fails
|
||||
|
||||
## Technical Details
|
||||
|
||||
### CSS Styling
|
||||
- **Modal**: Fixed position, z-index 9999, centered layout
|
||||
- **Content Card**: White background, rounded corners, shadow
|
||||
- **Progress Bar**: Linear gradient blue, smooth transitions
|
||||
- **Responsive**: Min-width 400px, max-width 500px
|
||||
|
||||
### JavaScript Functions Modified
|
||||
|
||||
#### `handleQZTrayPrint(selectedRow)`
|
||||
**Changes:**
|
||||
- Added modal element references
|
||||
- Show modal before printing starts
|
||||
- Update progress bar and counter in loop
|
||||
- Call database update endpoint after printing
|
||||
- Handle database update errors
|
||||
- Refresh table automatically
|
||||
- Close modal on completion or error
|
||||
|
||||
### Backend Integration
|
||||
|
||||
#### Endpoint Used: `/update_printed_status/<int:order_id>`
|
||||
- **Method**: POST
|
||||
- **Purpose**: Mark order as printed in database
|
||||
- **Authentication**: Requires superadmin, warehouse_manager, or etichete role
|
||||
- **Response**: JSON with success/error message
|
||||
|
||||
## User Experience Flow
|
||||
|
||||
1. User selects an order row in the table
|
||||
2. User clicks "Print Label (QZ Tray)" button
|
||||
3. Modal appears showing "Preparing to print..."
|
||||
4. Progress bar fills as each label prints
|
||||
5. Counter shows current progress (e.g., "7 / 10")
|
||||
6. After all labels print: "✅ All labels printed! Updating database..."
|
||||
7. Database updates with printed status
|
||||
8. Modal shows "✅ Complete! Refreshing table..."
|
||||
9. Modal closes automatically
|
||||
10. Success notification appears
|
||||
11. Table refreshes showing updated order status
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Visual Feedback**: Users see real-time progress instead of a frozen UI
|
||||
✅ **Status Clarity**: Clear messages about what's happening
|
||||
✅ **Automatic Updates**: Database and UI update without manual intervention
|
||||
✅ **Error Recovery**: Graceful handling of database update failures
|
||||
✅ **Professional UX**: Modern, polished user interface
|
||||
✅ **Non-Blocking**: Progress modal doesn't interfere with printing operation
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **print_module.html**
|
||||
- Added modal HTML structure
|
||||
- Added modal CSS styles
|
||||
- Updated `handleQZTrayPrint()` function
|
||||
- Added database update API call
|
||||
- Added automatic table refresh
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Modal appears when printing starts
|
||||
- [ ] Progress bar animates smoothly
|
||||
- [ ] Counter updates correctly (1/10, 2/10, etc.)
|
||||
- [ ] All labels print successfully
|
||||
- [ ] Database updates after printing
|
||||
- [ ] Table refreshes automatically
|
||||
- [ ] Modal closes after completion
|
||||
- [ ] Success notification appears
|
||||
- [ ] Error handling works (if DB update fails)
|
||||
- [ ] Modal closes on printing errors
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements:
|
||||
- Add "Cancel" button to stop printing mid-process
|
||||
- Show estimated time remaining
|
||||
- Add sound notification on completion
|
||||
- Log printing history with timestamps
|
||||
- Add printer status monitoring
|
||||
- Show print queue if multiple orders selected
|
||||
@@ -1,4 +0,0 @@
|
||||
* Serving Flask app 'app'
|
||||
* Debug mode: on
|
||||
Address already in use
|
||||
Port 8781 is in use by another program. Either identify and stop that program, or start the server with a different port.
|
||||
@@ -13,10 +13,8 @@ def create_app():
|
||||
db.init_app(app)
|
||||
|
||||
from app.routes import bp as main_bp, warehouse_bp
|
||||
from app.daily_mirror import daily_mirror_bp
|
||||
app.register_blueprint(main_bp, url_prefix='/')
|
||||
app.register_blueprint(warehouse_bp)
|
||||
app.register_blueprint(daily_mirror_bp)
|
||||
|
||||
# Add 'now' function to Jinja2 globals
|
||||
app.jinja_env.globals['now'] = datetime.now
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
"""
|
||||
Simple access control decorators for the 4-tier system
|
||||
"""
|
||||
from functools import wraps
|
||||
from flask import session, redirect, url_for, flash, request
|
||||
from .permissions_simple import check_access, ROLES
|
||||
|
||||
def requires_role(min_role_level=None, required_modules=None, page=None):
|
||||
"""
|
||||
Simple role-based access decorator
|
||||
|
||||
Args:
|
||||
min_role_level (int): Minimum role level required (50, 70, 90, 100)
|
||||
required_modules (list): Required modules for access
|
||||
page (str): Page name for automatic access checking
|
||||
"""
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# Check if user is logged in
|
||||
if 'user' not in session:
|
||||
flash('Please log in to access this page.')
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
user_role = session.get('role')
|
||||
user_modules = session.get('modules', [])
|
||||
|
||||
# If page is specified, use automatic access checking
|
||||
if page:
|
||||
if not check_access(user_role, user_modules, page):
|
||||
flash('Access denied: You do not have permission to access this page.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return f(*args, **kwargs)
|
||||
|
||||
# Manual role level checking
|
||||
if min_role_level:
|
||||
user_level = ROLES.get(user_role, {}).get('level', 0)
|
||||
if user_level < min_role_level:
|
||||
flash('Access denied: Insufficient privileges.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Module requirement checking
|
||||
if required_modules:
|
||||
if user_role in ['superadmin', 'admin']:
|
||||
# Superadmin and admin have access to all modules
|
||||
pass
|
||||
else:
|
||||
if not any(module in user_modules for module in required_modules):
|
||||
flash('Access denied: You do not have access to this module.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
return decorator
|
||||
|
||||
def superadmin_only(f):
|
||||
"""Decorator for superadmin-only pages"""
|
||||
return requires_role(min_role_level=100)(f)
|
||||
|
||||
def admin_plus(f):
|
||||
"""Decorator for admin and superadmin access"""
|
||||
return requires_role(min_role_level=90)(f)
|
||||
|
||||
def manager_plus(f):
|
||||
"""Decorator for manager, admin, and superadmin access"""
|
||||
return requires_role(min_role_level=70)(f)
|
||||
|
||||
def requires_quality_module(f):
|
||||
"""Decorator for quality module access"""
|
||||
return requires_role(required_modules=['quality'])(f)
|
||||
|
||||
def requires_warehouse_module(f):
|
||||
"""Decorator for warehouse module access"""
|
||||
return requires_role(required_modules=['warehouse'])(f)
|
||||
|
||||
def requires_labels_module(f):
|
||||
"""Decorator for labels module access"""
|
||||
return requires_role(required_modules=['labels'])(f)
|
||||
|
||||
def requires_daily_mirror_module(f):
|
||||
"""Decorator for daily mirror module access"""
|
||||
return requires_role(required_modules=['daily_mirror'])(f)
|
||||
|
||||
def quality_manager_plus(f):
|
||||
"""Decorator for quality module manager+ access"""
|
||||
return requires_role(min_role_level=70, required_modules=['quality'])(f)
|
||||
|
||||
def warehouse_manager_plus(f):
|
||||
"""Decorator for warehouse module manager+ access"""
|
||||
return requires_role(min_role_level=70, required_modules=['warehouse'])(f)
|
||||
|
||||
def labels_manager_plus(f):
|
||||
"""Decorator for labels module manager+ access"""
|
||||
return requires_role(min_role_level=70, required_modules=['labels'])(f)
|
||||
|
||||
def daily_mirror_manager_plus(f):
|
||||
"""Decorator for daily mirror module manager+ access"""
|
||||
return requires_role(min_role_level=70, required_modules=['daily_mirror'])(f)
|
||||
@@ -1,344 +0,0 @@
|
||||
-- Daily Mirror Database Schema
|
||||
-- Quality Recticel Production Tracking System
|
||||
-- Created: October 24, 2025
|
||||
|
||||
-- =============================================
|
||||
-- ORDERS DATA TABLES
|
||||
-- =============================================
|
||||
|
||||
-- Main Orders Table (from Vizual. Artic. Comenzi Deschise)
|
||||
CREATE TABLE IF NOT EXISTS dm_orders (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
order_id VARCHAR(50) UNIQUE NOT NULL,
|
||||
customer_code VARCHAR(50),
|
||||
customer_name VARCHAR(255),
|
||||
client_order VARCHAR(100),
|
||||
article_code VARCHAR(50),
|
||||
article_description TEXT,
|
||||
quantity_requested INT,
|
||||
delivery_date DATE,
|
||||
order_status VARCHAR(50),
|
||||
priority VARCHAR(20),
|
||||
product_group VARCHAR(100),
|
||||
order_date DATE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_order_id (order_id),
|
||||
INDEX idx_customer (customer_code),
|
||||
INDEX idx_article (article_code),
|
||||
INDEX idx_delivery_date (delivery_date),
|
||||
INDEX idx_order_date (order_date),
|
||||
INDEX idx_status (order_status)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- PRODUCTION DATA TABLES
|
||||
-- =============================================
|
||||
|
||||
-- Production Orders Table (from Comenzi Productie - Production orders Data sheet)
|
||||
CREATE TABLE IF NOT EXISTS dm_production_orders (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- Primary Identifiers
|
||||
production_order VARCHAR(50) UNIQUE NOT NULL,
|
||||
open_for_order_line VARCHAR(100), -- Concatenated: "Opened for Order" + "-" + "Linia"
|
||||
client_order_line VARCHAR(100), -- Concatenated: "Com. Achiz. Client" + "-" + "Nr. linie com. client"
|
||||
|
||||
-- Customer Information
|
||||
customer_code VARCHAR(50),
|
||||
customer_name VARCHAR(255),
|
||||
|
||||
-- Article Information
|
||||
article_code VARCHAR(100),
|
||||
article_description TEXT,
|
||||
quantity_requested INT,
|
||||
unit_of_measure VARCHAR(20),
|
||||
|
||||
-- Dates
|
||||
delivery_date DATE, -- SO Duedate
|
||||
opening_date DATE, -- Data Deschiderii
|
||||
closing_date DATE, -- Data Inchiderii
|
||||
data_planificare DATE, -- Data Planific.
|
||||
|
||||
-- Production Status
|
||||
production_status VARCHAR(50), -- Status (Inchis, etc.)
|
||||
|
||||
-- Machine Information
|
||||
machine_code VARCHAR(50), -- Masina cusut
|
||||
machine_type VARCHAR(50), -- Tip masina
|
||||
machine_number VARCHAR(20), -- Machine Number
|
||||
|
||||
-- Production Timeline
|
||||
end_of_quilting DATE, -- End of Quilting
|
||||
end_of_sewing DATE, -- End of Sewing
|
||||
|
||||
-- Quality Control Phase T1 (Prepared)
|
||||
phase_t1_prepared VARCHAR(50), -- Faza pregatit(T1)
|
||||
t1_operator_name VARCHAR(100), -- Nume complet T1
|
||||
t1_registration_date DATETIME, -- Data inregistrare T1
|
||||
|
||||
-- Quality Control Phase T2 (Cut/Quilted)
|
||||
phase_t2_cut VARCHAR(50), -- Faza taiat/matlasat(T2)
|
||||
t2_operator_name VARCHAR(100), -- Nume complet T2
|
||||
t2_registration_date DATETIME, -- Data inregistrare T2
|
||||
|
||||
-- Quality Control Phase T3 (Sewing)
|
||||
phase_t3_sewing VARCHAR(50), -- Faza cusut(T3)
|
||||
t3_operator_name VARCHAR(100), -- Nume complet T3
|
||||
t3_registration_date DATETIME, -- Data inregistrare T3
|
||||
|
||||
-- Additional Information
|
||||
design_number INT, -- Design number
|
||||
classification VARCHAR(100), -- Clasificare
|
||||
model_description VARCHAR(255), -- Descriere Model
|
||||
model_lb2 VARCHAR(255), -- Model Lb2
|
||||
needle_position DECIMAL(5,1), -- Needle Position
|
||||
needle_row VARCHAR(50), -- Needle row
|
||||
priority INT DEFAULT 0, -- Prioritate executie
|
||||
|
||||
-- Metadata
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
-- Indexes for Performance
|
||||
INDEX idx_production_order (production_order),
|
||||
INDEX idx_open_for_order_line (open_for_order_line),
|
||||
INDEX idx_client_order_line (client_order_line),
|
||||
INDEX idx_customer (customer_code),
|
||||
INDEX idx_article (article_code),
|
||||
INDEX idx_delivery_date (delivery_date),
|
||||
INDEX idx_status (production_status),
|
||||
INDEX idx_machine (machine_code),
|
||||
INDEX idx_quilting_date (end_of_quilting),
|
||||
INDEX idx_sewing_date (end_of_sewing),
|
||||
INDEX idx_data_planificare (data_planificare)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- DELIVERY DATA TABLES
|
||||
-- =============================================
|
||||
|
||||
-- Delivery/Shipment Table (from Articole livrate)
|
||||
CREATE TABLE IF NOT EXISTS dm_deliveries (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
shipment_id VARCHAR(50) UNIQUE NOT NULL,
|
||||
order_id VARCHAR(50),
|
||||
production_order VARCHAR(50),
|
||||
customer_code VARCHAR(50),
|
||||
customer_name VARCHAR(255),
|
||||
article_code VARCHAR(50),
|
||||
article_description TEXT,
|
||||
quantity_delivered INT,
|
||||
quantity_returned INT DEFAULT 0,
|
||||
|
||||
-- Delivery Timeline
|
||||
shipment_date DATE,
|
||||
delivery_date DATE,
|
||||
return_date DATE,
|
||||
|
||||
-- Delivery Status
|
||||
delivery_status VARCHAR(50), -- 'shipped', 'delivered', 'returned', 'partial'
|
||||
shipping_method VARCHAR(100),
|
||||
tracking_number VARCHAR(100),
|
||||
shipping_address TEXT,
|
||||
delivery_notes TEXT,
|
||||
|
||||
-- Financial
|
||||
unit_price DECIMAL(10,2),
|
||||
total_value DECIMAL(12,2),
|
||||
currency VARCHAR(3) DEFAULT 'RON',
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_shipment_id (shipment_id),
|
||||
INDEX idx_order_id (order_id),
|
||||
INDEX idx_production_order (production_order),
|
||||
INDEX idx_customer (customer_code),
|
||||
INDEX idx_article (article_code),
|
||||
INDEX idx_shipment_date (shipment_date),
|
||||
INDEX idx_delivery_date (delivery_date),
|
||||
INDEX idx_status (delivery_status)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- DAILY MIRROR AGGREGATION TABLES
|
||||
-- =============================================
|
||||
|
||||
-- Daily Summary Table (for fast reporting)
|
||||
CREATE TABLE IF NOT EXISTS dm_daily_summary (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
report_date DATE UNIQUE NOT NULL,
|
||||
|
||||
-- Orders Metrics
|
||||
orders_received INT DEFAULT 0,
|
||||
orders_quantity INT DEFAULT 0,
|
||||
orders_value DECIMAL(15,2) DEFAULT 0,
|
||||
unique_customers INT DEFAULT 0,
|
||||
|
||||
-- Production Metrics
|
||||
production_launched INT DEFAULT 0,
|
||||
production_finished INT DEFAULT 0,
|
||||
production_in_progress INT DEFAULT 0,
|
||||
quilting_completed INT DEFAULT 0,
|
||||
sewing_completed INT DEFAULT 0,
|
||||
|
||||
-- Delivery Metrics
|
||||
orders_shipped INT DEFAULT 0,
|
||||
orders_delivered INT DEFAULT 0,
|
||||
orders_returned INT DEFAULT 0,
|
||||
delivery_value DECIMAL(15,2) DEFAULT 0,
|
||||
|
||||
-- Efficiency Metrics
|
||||
on_time_deliveries INT DEFAULT 0,
|
||||
late_deliveries INT DEFAULT 0,
|
||||
active_operators INT DEFAULT 0,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_report_date (report_date)
|
||||
);
|
||||
|
||||
|
||||
-- =============================================
|
||||
-- CONFIGURATION AND LOOKUP TABLES
|
||||
-- =============================================
|
||||
|
||||
-- Customer Master
|
||||
CREATE TABLE IF NOT EXISTS dm_customers (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
customer_code VARCHAR(50) UNIQUE NOT NULL,
|
||||
customer_name VARCHAR(255) NOT NULL,
|
||||
customer_group VARCHAR(100),
|
||||
country VARCHAR(50),
|
||||
currency VARCHAR(3) DEFAULT 'RON',
|
||||
payment_terms VARCHAR(100),
|
||||
credit_limit DECIMAL(15,2),
|
||||
active BOOLEAN DEFAULT TRUE,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_customer_code (customer_code),
|
||||
INDEX idx_customer_name (customer_name),
|
||||
INDEX idx_customer_group (customer_group)
|
||||
);
|
||||
|
||||
-- Article Master
|
||||
CREATE TABLE IF NOT EXISTS dm_articles (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
article_code VARCHAR(50) UNIQUE NOT NULL,
|
||||
article_description TEXT NOT NULL,
|
||||
product_group VARCHAR(100),
|
||||
classification VARCHAR(100),
|
||||
unit_of_measure VARCHAR(20),
|
||||
standard_price DECIMAL(10,2),
|
||||
standard_time DECIMAL(8,2),
|
||||
active BOOLEAN DEFAULT TRUE,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_article_code (article_code),
|
||||
INDEX idx_product_group (product_group),
|
||||
INDEX idx_classification (classification)
|
||||
);
|
||||
|
||||
-- Machine Master
|
||||
CREATE TABLE IF NOT EXISTS dm_machines (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
machine_code VARCHAR(50) UNIQUE NOT NULL,
|
||||
machine_name VARCHAR(255),
|
||||
machine_type VARCHAR(50),
|
||||
machine_number VARCHAR(20),
|
||||
department VARCHAR(100),
|
||||
capacity_per_hour DECIMAL(8,2),
|
||||
active BOOLEAN DEFAULT TRUE,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_machine_code (machine_code),
|
||||
INDEX idx_machine_type (machine_type),
|
||||
INDEX idx_department (department)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- DATA IMPORT TRACKING
|
||||
-- =============================================
|
||||
|
||||
-- Track file uploads and data imports
|
||||
CREATE TABLE IF NOT EXISTS dm_import_log (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
file_type VARCHAR(50) NOT NULL, -- 'orders', 'production', 'delivery'
|
||||
upload_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
uploaded_by VARCHAR(100),
|
||||
records_processed INT DEFAULT 0,
|
||||
records_successful INT DEFAULT 0,
|
||||
records_failed INT DEFAULT 0,
|
||||
status VARCHAR(50) DEFAULT 'processing', -- 'processing', 'completed', 'failed'
|
||||
error_message TEXT,
|
||||
processing_time DECIMAL(8,2), -- seconds
|
||||
|
||||
INDEX idx_upload_date (upload_date),
|
||||
INDEX idx_file_type (file_type),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_uploaded_by (uploaded_by)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- VIEWS FOR DAILY MIRROR REPORTING
|
||||
-- =============================================
|
||||
|
||||
-- View: Current Production Status
|
||||
CREATE OR REPLACE VIEW v_daily_production_status AS
|
||||
SELECT
|
||||
DATE(p.data_planificare) as production_date,
|
||||
COUNT(*) as total_orders,
|
||||
SUM(p.quantity_requested) as total_quantity,
|
||||
SUM(CASE WHEN p.production_status = 'Inchis' THEN 1 ELSE 0 END) as completed_orders,
|
||||
SUM(CASE WHEN p.production_status != 'Inchis' THEN 1 ELSE 0 END) as pending_orders,
|
||||
SUM(CASE WHEN p.end_of_quilting IS NOT NULL THEN 1 ELSE 0 END) as quilting_done,
|
||||
SUM(CASE WHEN p.end_of_sewing IS NOT NULL THEN 1 ELSE 0 END) as sewing_done,
|
||||
COUNT(DISTINCT p.customer_code) as unique_customers,
|
||||
COUNT(DISTINCT p.machine_code) as machines_used
|
||||
FROM dm_production_orders p
|
||||
WHERE p.data_planificare >= CURDATE() - INTERVAL 30 DAY
|
||||
GROUP BY DATE(p.data_planificare)
|
||||
ORDER BY production_date DESC;
|
||||
|
||||
-- View: Quality Performance Summary
|
||||
CREATE OR REPLACE VIEW v_daily_quality_summary AS
|
||||
SELECT
|
||||
DATE(p.t1_registration_date) as scan_date,
|
||||
COUNT(*) as total_t1_scans,
|
||||
SUM(CASE WHEN p.t1_status = 0 THEN 1 ELSE 0 END) as t1_approved,
|
||||
ROUND(SUM(CASE WHEN p.t1_status = 0 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) as t1_approval_rate,
|
||||
COUNT(CASE WHEN p.t2_registration_date IS NOT NULL THEN 1 END) as total_t2_scans,
|
||||
SUM(CASE WHEN p.t2_status = 0 THEN 1 ELSE 0 END) as t2_approved,
|
||||
ROUND(SUM(CASE WHEN p.t2_status = 0 THEN 1 ELSE 0 END) / COUNT(CASE WHEN p.t2_registration_date IS NOT NULL THEN 1 END) * 100, 2) as t2_approval_rate,
|
||||
COUNT(DISTINCT p.t1_operator_name) as active_operators
|
||||
FROM dm_production_orders p
|
||||
WHERE p.t1_registration_date >= CURDATE() - INTERVAL 30 DAY
|
||||
GROUP BY DATE(p.t1_registration_date)
|
||||
ORDER BY scan_date DESC;
|
||||
|
||||
-- View: Delivery Performance
|
||||
CREATE OR REPLACE VIEW v_daily_delivery_summary AS
|
||||
SELECT
|
||||
d.delivery_date,
|
||||
COUNT(*) as total_deliveries,
|
||||
SUM(d.quantity_delivered) as total_quantity_delivered,
|
||||
SUM(d.total_value) as total_delivery_value,
|
||||
SUM(CASE WHEN d.delivery_date <= o.delivery_date THEN 1 ELSE 0 END) as on_time_deliveries,
|
||||
SUM(CASE WHEN d.delivery_date > o.delivery_date THEN 1 ELSE 0 END) as late_deliveries,
|
||||
COUNT(DISTINCT d.customer_code) as unique_customers
|
||||
FROM dm_deliveries d
|
||||
LEFT JOIN dm_orders o ON d.order_id = o.order_id
|
||||
WHERE d.delivery_date >= CURDATE() - INTERVAL 30 DAY
|
||||
AND d.delivery_status = 'delivered'
|
||||
GROUP BY d.delivery_date
|
||||
ORDER BY d.delivery_date DESC;
|
||||
@@ -1,840 +0,0 @@
|
||||
"""
|
||||
Daily Mirror Database Setup and Management
|
||||
Quality Recticel Application
|
||||
|
||||
This script creates the database schema and provides utilities for
|
||||
data import and Daily Mirror reporting functionality.
|
||||
"""
|
||||
|
||||
import mariadb
|
||||
import pandas as pd
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class DailyMirrorDatabase:
|
||||
def __init__(self, host='localhost', user='trasabilitate', password='Initial01!', database='trasabilitate'):
|
||||
self.host = host
|
||||
self.user = user
|
||||
self.password = password
|
||||
self.database = database
|
||||
self.connection = None
|
||||
|
||||
def connect(self):
|
||||
"""Establish database connection"""
|
||||
try:
|
||||
self.connection = mariadb.connect(
|
||||
host=self.host,
|
||||
user=self.user,
|
||||
password=self.password,
|
||||
database=self.database
|
||||
)
|
||||
logger.info("Database connection established")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Database connection failed: {e}")
|
||||
return False
|
||||
|
||||
def disconnect(self):
|
||||
"""Close database connection"""
|
||||
if self.connection:
|
||||
self.connection.close()
|
||||
logger.info("Database connection closed")
|
||||
|
||||
def create_database_schema(self):
|
||||
"""Create the Daily Mirror database schema"""
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
|
||||
# Read and execute the schema file
|
||||
schema_file = os.path.join(os.path.dirname(__file__), 'daily_mirror_database_schema.sql')
|
||||
|
||||
if not os.path.exists(schema_file):
|
||||
logger.error(f"Schema file not found: {schema_file}")
|
||||
return False
|
||||
|
||||
with open(schema_file, 'r') as file:
|
||||
schema_sql = file.read()
|
||||
|
||||
# Split by statements and execute each one
|
||||
statements = []
|
||||
current_statement = ""
|
||||
|
||||
for line in schema_sql.split('\n'):
|
||||
line = line.strip()
|
||||
if line and not line.startswith('--'):
|
||||
current_statement += line + " "
|
||||
if line.endswith(';'):
|
||||
statements.append(current_statement.strip())
|
||||
current_statement = ""
|
||||
|
||||
# Add any remaining statement
|
||||
if current_statement.strip():
|
||||
statements.append(current_statement.strip())
|
||||
|
||||
for statement in statements:
|
||||
if statement and any(statement.upper().startswith(cmd) for cmd in ['CREATE', 'ALTER', 'DROP', 'INSERT']):
|
||||
try:
|
||||
cursor.execute(statement)
|
||||
logger.info(f"Executed: {statement[:80]}...")
|
||||
except Exception as e:
|
||||
if "already exists" not in str(e).lower():
|
||||
logger.warning(f"Error executing statement: {e}")
|
||||
|
||||
self.connection.commit()
|
||||
logger.info("Database schema created successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating database schema: {e}")
|
||||
return False
|
||||
|
||||
def import_production_data(self, file_path):
|
||||
"""Import production data from Excel file (Production orders Data sheet OR DataSheet)"""
|
||||
try:
|
||||
# Read from "Production orders Data" sheet (new format) or "DataSheet" (old format)
|
||||
df = None
|
||||
sheet_used = None
|
||||
|
||||
# Try different engines (openpyxl for .xlsx, pyxlsb for .xlsb)
|
||||
engines_to_try = ['openpyxl', 'pyxlsb']
|
||||
|
||||
# Try different sheet names (new format first, then old format)
|
||||
sheet_names_to_try = ['Production orders Data', 'DataSheet']
|
||||
|
||||
for engine in engines_to_try:
|
||||
if df is not None:
|
||||
break
|
||||
|
||||
try:
|
||||
logger.info(f"Trying to read Excel file with engine: {engine}")
|
||||
excel_file = pd.ExcelFile(file_path, engine=engine)
|
||||
logger.info(f"Available sheets: {excel_file.sheet_names}")
|
||||
|
||||
# Try each sheet name
|
||||
for sheet_name in sheet_names_to_try:
|
||||
if sheet_name in excel_file.sheet_names:
|
||||
try:
|
||||
logger.info(f"Reading sheet '{sheet_name}'")
|
||||
df = pd.read_excel(file_path, sheet_name=sheet_name, engine=engine, header=0)
|
||||
sheet_used = f"{sheet_name} (engine: {engine})"
|
||||
logger.info(f"Successfully read from sheet: {sheet_used}")
|
||||
break
|
||||
except Exception as sheet_error:
|
||||
logger.warning(f"Failed to read sheet '{sheet_name}': {sheet_error}")
|
||||
continue
|
||||
|
||||
if df is not None:
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed with engine {engine}: {e}")
|
||||
continue
|
||||
|
||||
if df is None:
|
||||
raise Exception("Could not read Excel file. Please ensure it has a 'Production orders Data' or 'DataSheet' sheet.")
|
||||
|
||||
logger.info(f"Loaded production data from {sheet_used}: {len(df)} rows, {len(df.columns)} columns")
|
||||
logger.info(f"First 5 column names: {list(df.columns)[:5]}")
|
||||
|
||||
cursor = self.connection.cursor()
|
||||
success_count = 0
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
error_count = 0
|
||||
|
||||
# Prepare insert statement with new schema
|
||||
insert_sql = """
|
||||
INSERT INTO dm_production_orders (
|
||||
production_order, production_order_line, line_number,
|
||||
open_for_order_line, client_order_line,
|
||||
customer_code, customer_name, article_code, article_description,
|
||||
quantity_requested, unit_of_measure, delivery_date, opening_date,
|
||||
closing_date, data_planificare, production_status,
|
||||
machine_code, machine_type, machine_number,
|
||||
end_of_quilting, end_of_sewing,
|
||||
phase_t1_prepared, t1_operator_name, t1_registration_date,
|
||||
phase_t2_cut, t2_operator_name, t2_registration_date,
|
||||
phase_t3_sewing, t3_operator_name, t3_registration_date,
|
||||
design_number, classification, model_description, model_lb2,
|
||||
needle_position, needle_row, priority
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
open_for_order_line = VALUES(open_for_order_line),
|
||||
client_order_line = VALUES(client_order_line),
|
||||
customer_code = VALUES(customer_code),
|
||||
customer_name = VALUES(customer_name),
|
||||
article_code = VALUES(article_code),
|
||||
article_description = VALUES(article_description),
|
||||
quantity_requested = VALUES(quantity_requested),
|
||||
delivery_date = VALUES(delivery_date),
|
||||
production_status = VALUES(production_status),
|
||||
machine_code = VALUES(machine_code),
|
||||
end_of_quilting = VALUES(end_of_quilting),
|
||||
end_of_sewing = VALUES(end_of_sewing),
|
||||
phase_t1_prepared = VALUES(phase_t1_prepared),
|
||||
t1_operator_name = VALUES(t1_operator_name),
|
||||
t1_registration_date = VALUES(t1_registration_date),
|
||||
phase_t2_cut = VALUES(phase_t2_cut),
|
||||
t2_operator_name = VALUES(t2_operator_name),
|
||||
t2_registration_date = VALUES(t2_registration_date),
|
||||
phase_t3_sewing = VALUES(phase_t3_sewing),
|
||||
t3_operator_name = VALUES(t3_operator_name),
|
||||
t3_registration_date = VALUES(t3_registration_date),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
"""
|
||||
|
||||
for index, row in df.iterrows():
|
||||
try:
|
||||
# Create concatenated fields with dash separator
|
||||
opened_for_order = str(row.get('Opened for Order', '')).strip() if pd.notna(row.get('Opened for Order')) else ''
|
||||
linia = str(row.get('Linia', '')).strip() if pd.notna(row.get('Linia')) else ''
|
||||
open_for_order_line = f"{opened_for_order}-{linia}" if opened_for_order and linia else ''
|
||||
|
||||
com_achiz_client = str(row.get('Com. Achiz. Client', '')).strip() if pd.notna(row.get('Com. Achiz. Client')) else ''
|
||||
nr_linie_com_client = str(row.get('Nr. linie com. client', '')).strip() if pd.notna(row.get('Nr. linie com. client')) else ''
|
||||
client_order_line = f"{com_achiz_client}-{nr_linie_com_client}" if com_achiz_client and nr_linie_com_client else ''
|
||||
|
||||
# Helper function to safely get numeric values
|
||||
def safe_int(value, default=None):
|
||||
if pd.isna(value) or value == '':
|
||||
return default
|
||||
try:
|
||||
return int(float(value))
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
|
||||
def safe_float(value, default=None):
|
||||
if pd.isna(value) or value == '':
|
||||
return default
|
||||
try:
|
||||
return float(value)
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
|
||||
def safe_str(value, default=''):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
return str(value).strip()
|
||||
|
||||
# Prepare data tuple
|
||||
data = (
|
||||
safe_str(row.get('Comanda Productie')), # production_order
|
||||
open_for_order_line, # open_for_order_line (concatenated)
|
||||
client_order_line, # client_order_line (concatenated)
|
||||
safe_str(row.get('Cod. Client')), # customer_code
|
||||
safe_str(row.get('Customer Name')), # customer_name
|
||||
safe_str(row.get('Cod Articol')), # article_code
|
||||
safe_str(row.get('Descr. Articol.1')), # article_description
|
||||
safe_int(row.get('Cantitate Com. Prod.'), 0), # quantity_requested
|
||||
safe_str(row.get('U.M.')), # unit_of_measure
|
||||
self._parse_date(row.get('SO Duedate')), # delivery_date
|
||||
self._parse_date(row.get('Data Deschiderii')), # opening_date
|
||||
self._parse_date(row.get('Data Inchiderii')), # closing_date
|
||||
self._parse_date(row.get('Data Planific.')), # data_planificare
|
||||
safe_str(row.get('Status')), # production_status
|
||||
safe_str(row.get('Masina cusut')), # machine_code
|
||||
safe_str(row.get('Tip masina')), # machine_type
|
||||
safe_str(row.get('Machine Number')), # machine_number
|
||||
self._parse_date(row.get('End of Quilting')), # end_of_quilting
|
||||
self._parse_date(row.get('End of Sewing')), # end_of_sewing
|
||||
safe_str(row.get('T2')), # phase_t1_prepared (using T2 column)
|
||||
safe_str(row.get('Nume complet T2')), # t1_operator_name
|
||||
self._parse_datetime(row.get('Data inregistrare T2')), # t1_registration_date
|
||||
safe_str(row.get('T1')), # phase_t2_cut (using T1 column)
|
||||
safe_str(row.get('Nume complet T1')), # t2_operator_name
|
||||
self._parse_datetime(row.get('Data inregistrare T1')), # t2_registration_date
|
||||
safe_str(row.get('T3')), # phase_t3_sewing (using T3 column)
|
||||
safe_str(row.get('Nume complet T3')), # t3_operator_name
|
||||
self._parse_datetime(row.get('Data inregistrare T3')), # t3_registration_date
|
||||
safe_int(row.get('Design number')), # design_number
|
||||
safe_str(row.get('Clasificare')), # classification
|
||||
safe_str(row.get('Descriere Model')), # model_description
|
||||
safe_str(row.get('Model Lb2')), # model_lb2
|
||||
safe_float(row.get('Needle Position')), # needle_position
|
||||
safe_str(row.get('Needle row')), # needle_row
|
||||
safe_int(row.get('Prioritate executie'), 0) # priority
|
||||
)
|
||||
|
||||
cursor.execute(insert_sql, data)
|
||||
|
||||
# Check if row was inserted (created) or updated
|
||||
# In MySQL with ON DUPLICATE KEY UPDATE:
|
||||
# - rowcount = 1 means INSERT (new row created)
|
||||
# - rowcount = 2 means UPDATE (existing row updated)
|
||||
# - rowcount = 0 means no change
|
||||
if cursor.rowcount == 1:
|
||||
created_count += 1
|
||||
elif cursor.rowcount == 2:
|
||||
updated_count += 1
|
||||
|
||||
success_count += 1
|
||||
|
||||
except Exception as row_error:
|
||||
logger.warning(f"Error processing row {index}: {row_error}")
|
||||
# Log first few values of problematic row
|
||||
try:
|
||||
row_sample = {k: v for k, v in list(row.items())[:5]}
|
||||
logger.warning(f"Row data sample: {row_sample}")
|
||||
except:
|
||||
pass
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
self.connection.commit()
|
||||
logger.info(f"Production data import completed: {success_count} successful ({created_count} created, {updated_count} updated), {error_count} failed")
|
||||
|
||||
return {
|
||||
'success_count': success_count,
|
||||
'created_count': created_count,
|
||||
'updated_count': updated_count,
|
||||
'error_count': error_count,
|
||||
'total_rows': len(df)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error importing production data: {e}")
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
return None
|
||||
|
||||
def import_orders_data(self, file_path):
|
||||
"""Import orders data from Excel file with enhanced error handling and multi-line support"""
|
||||
try:
|
||||
# Ensure we have a database connection
|
||||
if not self.connection:
|
||||
self.connect()
|
||||
if not self.connection:
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': 'Could not establish database connection.'
|
||||
}
|
||||
|
||||
logger.info(f"Attempting to import orders data from: {file_path}")
|
||||
|
||||
# Check if file exists
|
||||
if not os.path.exists(file_path):
|
||||
logger.error(f"Orders file not found: {file_path}")
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': f'Orders file not found: {file_path}'
|
||||
}
|
||||
|
||||
# Read from DataSheet - the correct sheet for orders data
|
||||
try:
|
||||
df = pd.read_excel(file_path, sheet_name='DataSheet', engine='openpyxl', header=0)
|
||||
logger.info(f"Successfully read orders data from DataSheet: {len(df)} rows, {len(df.columns)} columns")
|
||||
logger.info(f"Available columns: {list(df.columns)[:15]}...")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to read DataSheet from orders file: {e}")
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': f'Could not read DataSheet from orders file: {e}'
|
||||
}
|
||||
|
||||
cursor = self.connection.cursor()
|
||||
success_count = 0
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
error_count = 0
|
||||
|
||||
# Prepare insert statement matching the actual table structure
|
||||
insert_sql = """
|
||||
INSERT INTO dm_orders (
|
||||
order_line, order_id, line_number, customer_code, customer_name,
|
||||
client_order_line, article_code, article_description,
|
||||
quantity_requested, balance, unit_of_measure, delivery_date, order_date,
|
||||
order_status, article_status, priority, product_group, production_order,
|
||||
production_status, model, closed
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
order_id = VALUES(order_id),
|
||||
line_number = VALUES(line_number),
|
||||
customer_code = VALUES(customer_code),
|
||||
customer_name = VALUES(customer_name),
|
||||
client_order_line = VALUES(client_order_line),
|
||||
article_code = VALUES(article_code),
|
||||
article_description = VALUES(article_description),
|
||||
quantity_requested = VALUES(quantity_requested),
|
||||
balance = VALUES(balance),
|
||||
unit_of_measure = VALUES(unit_of_measure),
|
||||
delivery_date = VALUES(delivery_date),
|
||||
order_date = VALUES(order_date),
|
||||
order_status = VALUES(order_status),
|
||||
article_status = VALUES(article_status),
|
||||
priority = VALUES(priority),
|
||||
product_group = VALUES(product_group),
|
||||
production_order = VALUES(production_order),
|
||||
production_status = VALUES(production_status),
|
||||
model = VALUES(model),
|
||||
closed = VALUES(closed),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
"""
|
||||
|
||||
# Safe value helper functions
|
||||
def safe_str(value, default=''):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
return str(value).strip() if value != '' else default
|
||||
|
||||
def safe_int(value, default=None):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
try:
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
if value == '':
|
||||
return default
|
||||
return int(float(value))
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
|
||||
def safe_float(value, default=None):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
try:
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
if value == '':
|
||||
return default
|
||||
return float(value)
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
|
||||
# Process each row with the new schema
|
||||
for index, row in df.iterrows():
|
||||
try:
|
||||
# Create concatenated unique keys
|
||||
order_id = safe_str(row.get('Comanda'), f'ORD_{index:06d}')
|
||||
line_number = safe_int(row.get('Linie'), 1)
|
||||
order_line = f"{order_id}-{line_number}"
|
||||
|
||||
# Create concatenated client order line
|
||||
client_order = safe_str(row.get('Com. Achiz. Client'))
|
||||
client_order_line_num = safe_str(row.get('Nr. linie com. client'))
|
||||
client_order_line = f"{client_order}-{client_order_line_num}" if client_order and client_order_line_num else ''
|
||||
|
||||
# Map all fields from Excel to database (21 fields, removed client_order)
|
||||
data = (
|
||||
order_line, # order_line (UNIQUE key: order_id-line_number)
|
||||
order_id, # order_id
|
||||
line_number, # line_number
|
||||
safe_str(row.get('Cod. Client')), # customer_code
|
||||
safe_str(row.get('Customer Name')), # customer_name
|
||||
client_order_line, # client_order_line (concatenated)
|
||||
safe_str(row.get('Cod Articol')), # article_code
|
||||
safe_str(row.get('Part Description')), # article_description
|
||||
safe_int(row.get('Cantitate')), # quantity_requested
|
||||
safe_float(row.get('Balanta')), # balance
|
||||
safe_str(row.get('U.M.')), # unit_of_measure
|
||||
self._parse_date(row.get('Data livrare')), # delivery_date
|
||||
self._parse_date(row.get('Data Comenzii')), # order_date
|
||||
safe_str(row.get('Statut Comanda')), # order_status
|
||||
safe_str(row.get('Stare Articol')), # article_status
|
||||
safe_int(row.get('Prioritate')), # priority
|
||||
safe_str(row.get('Grup')), # product_group
|
||||
safe_str(row.get('Comanda Productie')), # production_order
|
||||
safe_str(row.get('Stare CP')), # production_status
|
||||
safe_str(row.get('Model')), # model
|
||||
safe_str(row.get('Inchis')) # closed
|
||||
)
|
||||
|
||||
cursor.execute(insert_sql, data)
|
||||
|
||||
# Track created vs updated
|
||||
if cursor.rowcount == 1:
|
||||
created_count += 1
|
||||
elif cursor.rowcount == 2:
|
||||
updated_count += 1
|
||||
|
||||
success_count += 1
|
||||
|
||||
except Exception as row_error:
|
||||
logger.warning(f"Error processing row {index} (order_line: {order_line if 'order_line' in locals() else 'unknown'}): {row_error}")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
self.connection.commit()
|
||||
logger.info(f"Orders import completed: {success_count} successful ({created_count} created, {updated_count} updated), {error_count} errors")
|
||||
|
||||
return {
|
||||
'success_count': success_count,
|
||||
'created_count': created_count,
|
||||
'updated_count': updated_count,
|
||||
'error_count': error_count,
|
||||
'total_rows': len(df),
|
||||
'error_message': None if error_count == 0 else f'{error_count} rows failed to import'
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error importing orders data: {e}")
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': str(e)
|
||||
}
|
||||
|
||||
def import_delivery_data(self, file_path):
|
||||
"""Import delivery data from Excel file with enhanced error handling"""
|
||||
try:
|
||||
# Ensure we have a database connection
|
||||
if not self.connection:
|
||||
self.connect()
|
||||
if not self.connection:
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': 'Could not establish database connection.'
|
||||
}
|
||||
|
||||
logger.info(f"Attempting to import delivery data from: {file_path}")
|
||||
|
||||
# Check if file exists
|
||||
if not os.path.exists(file_path):
|
||||
logger.error(f"Delivery file not found: {file_path}")
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': f'Delivery file not found: {file_path}'
|
||||
}
|
||||
|
||||
# Try to get sheet names first
|
||||
try:
|
||||
excel_file = pd.ExcelFile(file_path)
|
||||
sheet_names = excel_file.sheet_names
|
||||
logger.info(f"Available sheets in delivery file: {sheet_names}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not get sheet names: {e}")
|
||||
sheet_names = ['DataSheet', 'Sheet1']
|
||||
|
||||
# Try multiple approaches to read the Excel file
|
||||
df = None
|
||||
sheet_used = None
|
||||
approaches = [
|
||||
('openpyxl', 0, 'read_only'),
|
||||
('openpyxl', 0, 'normal'),
|
||||
('openpyxl', 1, 'normal'),
|
||||
('xlrd', 0, 'normal') if file_path.endswith('.xls') else None,
|
||||
('default', 0, 'normal')
|
||||
]
|
||||
|
||||
for approach in approaches:
|
||||
if approach is None:
|
||||
continue
|
||||
|
||||
engine, sheet_name, mode = approach
|
||||
try:
|
||||
logger.info(f"Trying to read delivery data with engine: {engine}, sheet: {sheet_name}, mode: {mode}")
|
||||
|
||||
if engine == 'default':
|
||||
df = pd.read_excel(file_path, sheet_name=sheet_name, header=0)
|
||||
elif mode == 'read_only':
|
||||
df = pd.read_excel(file_path, sheet_name=sheet_name, engine=engine, header=0)
|
||||
else:
|
||||
df = pd.read_excel(file_path, sheet_name=sheet_name, engine=engine, header=0)
|
||||
|
||||
sheet_used = f"{engine} (sheet: {sheet_name}, mode: {mode})"
|
||||
logger.info(f"Successfully read delivery data with: {sheet_used}")
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed with {engine}, sheet {sheet_name}, mode {mode}: {e}")
|
||||
continue
|
||||
|
||||
if df is None:
|
||||
logger.error("Could not read the delivery file with any method")
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': 'Could not read the delivery Excel file. The file may have formatting issues or be corrupted.'
|
||||
}
|
||||
|
||||
logger.info(f"Loaded delivery data from {sheet_used}: {len(df)} rows, {len(df.columns)} columns")
|
||||
logger.info(f"Available columns: {list(df.columns)[:10]}...")
|
||||
|
||||
cursor = self.connection.cursor()
|
||||
success_count = 0
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
error_count = 0
|
||||
|
||||
# Prepare insert statement for deliveries - simple INSERT, every Excel row gets a database row
|
||||
insert_sql = """
|
||||
INSERT INTO dm_deliveries (
|
||||
shipment_id, order_id, client_order_line, customer_code, customer_name,
|
||||
article_code, article_description, quantity_delivered,
|
||||
shipment_date, delivery_date, delivery_status, total_value
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
# Process each row with the actual column mapping and better null handling
|
||||
for index, row in df.iterrows():
|
||||
try:
|
||||
# Safe value helper functions
|
||||
def safe_str(value, default=''):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
return str(value).strip() if value != '' else default
|
||||
|
||||
def safe_int(value, default=None):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
try:
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
if value == '':
|
||||
return default
|
||||
return int(float(value))
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
|
||||
def safe_float(value, default=None):
|
||||
if pd.isna(value):
|
||||
return default
|
||||
try:
|
||||
if isinstance(value, str):
|
||||
value = value.strip()
|
||||
if value == '':
|
||||
return default
|
||||
return float(value)
|
||||
except (ValueError, TypeError):
|
||||
return default
|
||||
|
||||
# Create concatenated client order line: Com. Achiz. Client + "-" + Linie
|
||||
client_order = safe_str(row.get('Com. Achiz. Client'))
|
||||
linie = safe_str(row.get('Linie'))
|
||||
client_order_line = f"{client_order}-{linie}" if client_order and linie else ''
|
||||
|
||||
# Map columns based on the actual Articole livrate_returnate format
|
||||
data = (
|
||||
safe_str(row.get('Document Number'), f'SH_{index:06d}'), # Shipment ID
|
||||
safe_str(row.get('Comanda')), # Order ID
|
||||
client_order_line, # Client Order Line (concatenated)
|
||||
safe_str(row.get('Cod. Client')), # Customer Code
|
||||
safe_str(row.get('Nume client')), # Customer Name
|
||||
safe_str(row.get('Cod Articol')), # Article Code
|
||||
safe_str(row.get('Part Description')), # Article Description
|
||||
safe_int(row.get('Cantitate')), # Quantity Delivered
|
||||
self._parse_date(row.get('Data')), # Shipment Date
|
||||
self._parse_date(row.get('Data')), # Delivery Date (same as shipment for now)
|
||||
safe_str(row.get('Stare'), 'DELIVERED'), # Delivery Status
|
||||
safe_float(row.get('Total Price')) # Total Value
|
||||
)
|
||||
|
||||
cursor.execute(insert_sql, data)
|
||||
|
||||
# Track created rows (simple INSERT always creates)
|
||||
if cursor.rowcount == 1:
|
||||
created_count += 1
|
||||
|
||||
success_count += 1
|
||||
|
||||
except Exception as row_error:
|
||||
logger.warning(f"Error processing delivery row {index}: {row_error}")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
self.connection.commit()
|
||||
logger.info(f"Delivery import completed: {success_count} successful, {error_count} errors")
|
||||
|
||||
return {
|
||||
'success_count': success_count,
|
||||
'created_count': created_count,
|
||||
'updated_count': updated_count,
|
||||
'error_count': error_count,
|
||||
'total_rows': len(df),
|
||||
'error_message': None if error_count == 0 else f'{error_count} rows failed to import'
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error importing delivery data: {e}")
|
||||
return {
|
||||
'success_count': 0,
|
||||
'error_count': 1,
|
||||
'total_rows': 0,
|
||||
'error_message': str(e)
|
||||
}
|
||||
|
||||
def generate_daily_summary(self, report_date=None):
|
||||
"""Generate daily summary for Daily Mirror reporting"""
|
||||
if not report_date:
|
||||
report_date = datetime.now().date()
|
||||
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
|
||||
# Check if summary already exists for this date
|
||||
cursor.execute("SELECT id FROM dm_daily_summary WHERE report_date = ?", (report_date,))
|
||||
existing = cursor.fetchone()
|
||||
|
||||
# Get production metrics
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
COUNT(*) as total_orders,
|
||||
SUM(quantity_requested) as total_quantity,
|
||||
SUM(CASE WHEN production_status = 'Inchis' THEN 1 ELSE 0 END) as completed_orders,
|
||||
SUM(CASE WHEN end_of_quilting IS NOT NULL THEN 1 ELSE 0 END) as quilting_done,
|
||||
SUM(CASE WHEN end_of_sewing IS NOT NULL THEN 1 ELSE 0 END) as sewing_done,
|
||||
COUNT(DISTINCT customer_code) as unique_customers
|
||||
FROM dm_production_orders
|
||||
WHERE DATE(data_planificare) = ?
|
||||
""", (report_date,))
|
||||
|
||||
production_metrics = cursor.fetchone()
|
||||
|
||||
# Get active operators count
|
||||
cursor.execute("""
|
||||
SELECT COUNT(DISTINCT CASE
|
||||
WHEN t1_operator_name IS NOT NULL THEN t1_operator_name
|
||||
WHEN t2_operator_name IS NOT NULL THEN t2_operator_name
|
||||
WHEN t3_operator_name IS NOT NULL THEN t3_operator_name
|
||||
END) as active_operators
|
||||
FROM dm_production_orders
|
||||
WHERE DATE(data_planificare) = ?
|
||||
""", (report_date,))
|
||||
|
||||
operator_metrics = cursor.fetchone()
|
||||
active_operators = operator_metrics[0] or 0
|
||||
|
||||
if existing:
|
||||
# Update existing summary
|
||||
update_sql = """
|
||||
UPDATE dm_daily_summary SET
|
||||
orders_quantity = ?, production_launched = ?, production_finished = ?,
|
||||
quilting_completed = ?, sewing_completed = ?, unique_customers = ?,
|
||||
active_operators = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE report_date = ?
|
||||
"""
|
||||
cursor.execute(update_sql, (
|
||||
production_metrics[1] or 0, production_metrics[0] or 0, production_metrics[2] or 0,
|
||||
production_metrics[3] or 0, production_metrics[4] or 0, production_metrics[5] or 0,
|
||||
active_operators, report_date
|
||||
))
|
||||
else:
|
||||
# Insert new summary
|
||||
insert_sql = """
|
||||
INSERT INTO dm_daily_summary (
|
||||
report_date, orders_quantity, production_launched, production_finished,
|
||||
quilting_completed, sewing_completed, unique_customers, active_operators
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
cursor.execute(insert_sql, (
|
||||
report_date, production_metrics[1] or 0, production_metrics[0] or 0, production_metrics[2] or 0,
|
||||
production_metrics[3] or 0, production_metrics[4] or 0, production_metrics[5] or 0,
|
||||
active_operators
|
||||
))
|
||||
|
||||
self.connection.commit()
|
||||
logger.info(f"Daily summary generated for {report_date}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating daily summary: {e}")
|
||||
return False
|
||||
|
||||
def clear_production_orders(self):
|
||||
"""Delete all rows from the Daily Mirror production orders table"""
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute("DELETE FROM dm_production_orders")
|
||||
self.connection.commit()
|
||||
logger.info("All production orders deleted from dm_production_orders table.")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting production orders: {e}")
|
||||
return False
|
||||
|
||||
def clear_orders(self):
|
||||
"""Delete all rows from the Daily Mirror orders table"""
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute("DELETE FROM dm_orders")
|
||||
self.connection.commit()
|
||||
logger.info("All orders deleted from dm_orders table.")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting orders: {e}")
|
||||
return False
|
||||
|
||||
def clear_delivery(self):
|
||||
"""Delete all rows from the Daily Mirror delivery table"""
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute("DELETE FROM dm_deliveries")
|
||||
self.connection.commit()
|
||||
logger.info("All delivery records deleted from dm_deliveries table.")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting delivery records: {e}")
|
||||
return False
|
||||
|
||||
def _parse_date(self, date_value):
|
||||
"""Parse date with better null handling"""
|
||||
if pd.isna(date_value) or date_value == 'nan' or date_value is None or date_value == '':
|
||||
return None
|
||||
|
||||
try:
|
||||
if isinstance(date_value, str):
|
||||
# Handle various date formats
|
||||
for fmt in ['%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%d.%m.%Y']:
|
||||
try:
|
||||
return datetime.strptime(date_value, fmt).date()
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
elif hasattr(date_value, 'date'):
|
||||
return date_value.date()
|
||||
elif isinstance(date_value, datetime):
|
||||
return date_value.date()
|
||||
|
||||
return None # If all parsing attempts fail
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Error parsing date {date_value}: {e}")
|
||||
return None
|
||||
|
||||
def _parse_datetime(self, datetime_value):
|
||||
"""Parse datetime value from Excel"""
|
||||
if pd.isna(datetime_value):
|
||||
return None
|
||||
if isinstance(datetime_value, str) and datetime_value == '00:00:00':
|
||||
return None
|
||||
return datetime_value
|
||||
|
||||
def setup_daily_mirror_database():
|
||||
"""Setup the Daily Mirror database schema"""
|
||||
db = DailyMirrorDatabase()
|
||||
|
||||
if not db.connect():
|
||||
return False
|
||||
|
||||
try:
|
||||
success = db.create_database_schema()
|
||||
if success:
|
||||
print("✅ Daily Mirror database schema created successfully!")
|
||||
|
||||
# Generate sample daily summary for today
|
||||
db.generate_daily_summary()
|
||||
|
||||
return success
|
||||
finally:
|
||||
db.disconnect()
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_daily_mirror_database()
|
||||
151
py_app/app/db_create_scripts/add_printed_labels_column.py
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Database script to add the printed_labels column to the order_for_labels table
|
||||
This column will track whether labels have been printed for each order (boolean: 0=false, 1=true)
|
||||
Default value: 0 (false)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import mariadb
|
||||
from flask import Flask
|
||||
|
||||
# Add the app directory to the path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
def get_db_connection():
|
||||
"""Get database connection using settings from external_server.conf"""
|
||||
# Go up two levels from this script to reach py_app directory, then to instance
|
||||
app_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
settings_file = os.path.join(app_root, 'instance', 'external_server.conf')
|
||||
|
||||
settings = {}
|
||||
with open(settings_file, 'r') as f:
|
||||
for line in f:
|
||||
key, value = line.strip().split('=', 1)
|
||||
settings[key] = value
|
||||
|
||||
return mariadb.connect(
|
||||
user=settings['username'],
|
||||
password=settings['password'],
|
||||
host=settings['server_domain'],
|
||||
port=int(settings['port']),
|
||||
database=settings['database_name']
|
||||
)
|
||||
|
||||
def add_printed_labels_column():
|
||||
"""
|
||||
Adds the printed_labels column to the order_for_labels table after the line_number column
|
||||
Column type: TINYINT(1) (boolean: 0=false, 1=true)
|
||||
Default value: 0 (false)
|
||||
"""
|
||||
try:
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if table exists
|
||||
cursor.execute("SHOW TABLES LIKE 'order_for_labels'")
|
||||
result = cursor.fetchone()
|
||||
|
||||
if not result:
|
||||
print("❌ Table 'order_for_labels' does not exist. Please create it first.")
|
||||
return False
|
||||
|
||||
# Check if column already exists
|
||||
cursor.execute("SHOW COLUMNS FROM order_for_labels LIKE 'printed_labels'")
|
||||
column_exists = cursor.fetchone()
|
||||
|
||||
if column_exists:
|
||||
print("ℹ️ Column 'printed_labels' already exists.")
|
||||
# Show current structure
|
||||
cursor.execute("DESCRIBE order_for_labels")
|
||||
columns = cursor.fetchall()
|
||||
print("\n📋 Current table structure:")
|
||||
for col in columns:
|
||||
null_info = 'NULL' if col[2] == 'YES' else 'NOT NULL'
|
||||
default_info = f" DEFAULT {col[4]}" if col[4] else ""
|
||||
print(f" 📌 {col[0]:<25} {col[1]:<20} {null_info}{default_info}")
|
||||
else:
|
||||
# Add the column after line_number
|
||||
alter_table_sql = """
|
||||
ALTER TABLE order_for_labels
|
||||
ADD COLUMN printed_labels TINYINT(1) NOT NULL DEFAULT 0
|
||||
COMMENT 'Boolean flag: 0=labels not printed, 1=labels printed'
|
||||
AFTER line_number
|
||||
"""
|
||||
|
||||
cursor.execute(alter_table_sql)
|
||||
conn.commit()
|
||||
print("✅ Column 'printed_labels' added successfully!")
|
||||
|
||||
# Show the updated structure
|
||||
cursor.execute("DESCRIBE order_for_labels")
|
||||
columns = cursor.fetchall()
|
||||
print("\n📋 Updated table structure:")
|
||||
for col in columns:
|
||||
null_info = 'NULL' if col[2] == 'YES' else 'NOT NULL'
|
||||
default_info = f" DEFAULT {col[4]}" if col[4] else ""
|
||||
highlight = "🆕 " if col[0] == 'printed_labels' else " "
|
||||
print(f"{highlight}{col[0]:<25} {col[1]:<20} {null_info}{default_info}")
|
||||
|
||||
# Show count of existing records that will have printed_labels = 0
|
||||
cursor.execute("SELECT COUNT(*) FROM order_for_labels")
|
||||
count = cursor.fetchone()[0]
|
||||
if count > 0:
|
||||
print(f"\n📊 {count} existing records now have printed_labels = 0 (false)")
|
||||
|
||||
conn.close()
|
||||
|
||||
except mariadb.Error as e:
|
||||
print(f"❌ Database error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def verify_column():
|
||||
"""Verify the column was added correctly"""
|
||||
try:
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Test the column functionality
|
||||
cursor.execute("SELECT COUNT(*) as total, SUM(printed_labels) as printed FROM order_for_labels")
|
||||
result = cursor.fetchone()
|
||||
|
||||
if result:
|
||||
total, printed = result
|
||||
print(f"\n🔍 Verification:")
|
||||
print(f" 📦 Total orders: {total}")
|
||||
print(f" 🖨️ Printed orders: {printed or 0}")
|
||||
print(f" 📄 Unprinted orders: {total - (printed or 0)}")
|
||||
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Verification failed: {e}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🔧 Adding printed_labels column to order_for_labels table...")
|
||||
print("="*60)
|
||||
|
||||
success = add_printed_labels_column()
|
||||
|
||||
if success:
|
||||
print("\n🔍 Verifying column addition...")
|
||||
verify_column()
|
||||
print("\n✅ Database modification completed successfully!")
|
||||
print("\n📝 Column Details:")
|
||||
print(" • Name: printed_labels")
|
||||
print(" • Type: TINYINT(1) (boolean)")
|
||||
print(" • Default: 0 (false - labels not printed)")
|
||||
print(" • Values: 0 = not printed, 1 = printed")
|
||||
print(" • Position: After line_number column")
|
||||
else:
|
||||
print("\n❌ Database modification failed!")
|
||||
|
||||
print("="*60)
|
||||
@@ -5,7 +5,7 @@ db_config = {
|
||||
"user": "trasabilitate",
|
||||
"password": "Initial01!",
|
||||
"host": "localhost",
|
||||
"database": "trasabilitate"
|
||||
"database": "trasabilitate_database"
|
||||
}
|
||||
|
||||
# Connect to the database
|
||||
@@ -6,7 +6,7 @@ db_config = {
|
||||
"user": "trasabilitate",
|
||||
"password": "Initial01!",
|
||||
"host": "localhost",
|
||||
"database": "trasabilitate"
|
||||
"database": "trasabilitate_database"
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -5,7 +5,7 @@ db_config = {
|
||||
"user": "trasabilitate",
|
||||
"password": "Initial01!",
|
||||
"host": "localhost",
|
||||
"database": "trasabilitate"
|
||||
"database": "trasabilitate_database"
|
||||
}
|
||||
|
||||
# Connect to the database
|
||||
@@ -5,7 +5,7 @@ db_config = {
|
||||
"user": "trasabilitate",
|
||||
"password": "Initial01!",
|
||||
"host": "localhost",
|
||||
"database": "trasabilitate"
|
||||
"database": "trasabilitate_database"
|
||||
}
|
||||
|
||||
# Connect to the database
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Docker-compatible Database Setup Script
|
||||
Reads configuration from environment variables or config file
|
||||
"""
|
||||
|
||||
import mariadb
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
def get_db_config():
|
||||
"""Get database configuration from environment or config file"""
|
||||
# Try environment variables first (Docker)
|
||||
if os.getenv('DB_HOST'):
|
||||
return {
|
||||
"user": os.getenv('DB_USER', 'trasabilitate'),
|
||||
"password": os.getenv('DB_PASSWORD', 'Initial01!'),
|
||||
"host": os.getenv('DB_HOST', 'localhost'),
|
||||
"port": int(os.getenv('DB_PORT', '3306')),
|
||||
"database": os.getenv('DB_NAME', 'trasabilitate')
|
||||
}
|
||||
|
||||
# Fallback to config file (traditional deployment)
|
||||
config_file = os.path.join(os.path.dirname(__file__), '../../instance/external_server.conf')
|
||||
if os.path.exists(config_file):
|
||||
settings = {}
|
||||
with open(config_file, 'r') as f:
|
||||
for line in f:
|
||||
if '=' in line:
|
||||
key, value = line.strip().split('=', 1)
|
||||
settings[key] = value
|
||||
|
||||
return {
|
||||
"user": settings.get('username', 'trasabilitate'),
|
||||
"password": settings.get('password', 'Initial01!'),
|
||||
"host": settings.get('server_domain', 'localhost'),
|
||||
"port": int(settings.get('port', '3306')),
|
||||
"database": settings.get('database_name', 'trasabilitate')
|
||||
}
|
||||
|
||||
# Default configuration
|
||||
return {
|
||||
"user": "trasabilitate",
|
||||
"password": "Initial01!",
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"database": "trasabilitate"
|
||||
}
|
||||
|
||||
def print_step(step_num, description):
|
||||
"""Print formatted step information"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Step {step_num}: {description}")
|
||||
print('='*60)
|
||||
|
||||
def print_success(message):
|
||||
"""Print success message"""
|
||||
print(f"✅ {message}")
|
||||
|
||||
def print_error(message):
|
||||
"""Print error message"""
|
||||
print(f"❌ {message}")
|
||||
|
||||
# Get configuration
|
||||
DB_CONFIG = get_db_config()
|
||||
|
||||
print(f"Using database configuration: {DB_CONFIG['user']}@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}")
|
||||
|
||||
# Import the rest from the original setup script
|
||||
@@ -1,722 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Complete Database Setup Script for Trasabilitate Application
|
||||
This script creates all necessary database tables, triggers, and initial data
|
||||
for quick deployment of the application.
|
||||
|
||||
Usage: python3 setup_complete_database.py
|
||||
Supports both traditional and Docker deployments via environment variables.
|
||||
"""
|
||||
|
||||
import mariadb
|
||||
import sqlite3
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# Database configuration - supports environment variables (Docker) or defaults
|
||||
DB_CONFIG = {
|
||||
"user": os.getenv("DB_USER", "trasabilitate"),
|
||||
"password": os.getenv("DB_PASSWORD", "Initial01!"),
|
||||
"host": os.getenv("DB_HOST", "localhost"),
|
||||
"port": int(os.getenv("DB_PORT", "3306")),
|
||||
"database": os.getenv("DB_NAME", "trasabilitate")
|
||||
}
|
||||
|
||||
def print_step(step_num, description):
|
||||
"""Print formatted step information"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Step {step_num}: {description}")
|
||||
print('='*60)
|
||||
|
||||
def print_success(message):
|
||||
"""Print success message"""
|
||||
print(f"✅ {message}")
|
||||
|
||||
def print_error(message):
|
||||
"""Print error message"""
|
||||
print(f"❌ {message}")
|
||||
|
||||
def test_database_connection():
|
||||
"""Test if we can connect to the database"""
|
||||
print_step(1, "Testing Database Connection")
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
print_success("Successfully connected to MariaDB database 'trasabilitate'")
|
||||
conn.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
print_error(f"Failed to connect to database: {e}")
|
||||
print("\nPlease ensure:")
|
||||
print("1. MariaDB is running")
|
||||
print("2. Database 'trasabilitate' exists")
|
||||
print("3. User 'trasabilitate' has been created with password 'Initial01!'")
|
||||
print("4. User has all privileges on the database")
|
||||
return False
|
||||
|
||||
def create_scan_tables():
|
||||
"""Create scan1_orders and scanfg_orders tables"""
|
||||
print_step(2, "Creating Scan Tables (scan1_orders & scanfg_orders)")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Create scan1_orders table
|
||||
scan1_table_query = """
|
||||
CREATE TABLE IF NOT EXISTS scan1_orders (
|
||||
Id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
operator_code VARCHAR(4) NOT NULL,
|
||||
CP_full_code VARCHAR(15) NOT NULL UNIQUE,
|
||||
OC1_code VARCHAR(4) NOT NULL,
|
||||
OC2_code VARCHAR(4) NOT NULL,
|
||||
CP_base_code VARCHAR(10) GENERATED ALWAYS AS (LEFT(CP_full_code, 10)) STORED,
|
||||
quality_code INT(3) NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
time TIME NOT NULL,
|
||||
approved_quantity INT DEFAULT 0,
|
||||
rejected_quantity INT DEFAULT 0
|
||||
);
|
||||
"""
|
||||
cursor.execute(scan1_table_query)
|
||||
print_success("Table 'scan1_orders' created successfully")
|
||||
|
||||
# Create scanfg_orders table
|
||||
scanfg_table_query = """
|
||||
CREATE TABLE IF NOT EXISTS scanfg_orders (
|
||||
Id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
operator_code VARCHAR(4) NOT NULL,
|
||||
CP_full_code VARCHAR(15) NOT NULL UNIQUE,
|
||||
OC1_code VARCHAR(4) NOT NULL,
|
||||
OC2_code VARCHAR(4) NOT NULL,
|
||||
CP_base_code VARCHAR(10) GENERATED ALWAYS AS (LEFT(CP_full_code, 10)) STORED,
|
||||
quality_code INT(3) NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
time TIME NOT NULL,
|
||||
approved_quantity INT DEFAULT 0,
|
||||
rejected_quantity INT DEFAULT 0
|
||||
);
|
||||
"""
|
||||
cursor.execute(scanfg_table_query)
|
||||
print_success("Table 'scanfg_orders' created successfully")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create scan tables: {e}")
|
||||
return False
|
||||
|
||||
def create_order_for_labels_table():
|
||||
"""Create order_for_labels table
|
||||
|
||||
This table stores production orders for label generation.
|
||||
Includes columns added for print module functionality:
|
||||
- printed_labels: Track if labels have been printed (0=no, 1=yes)
|
||||
- data_livrare: Delivery date from CSV uploads
|
||||
- dimensiune: Product dimensions from CSV uploads
|
||||
"""
|
||||
print_step(3, "Creating Order for Labels Table")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
order_labels_query = """
|
||||
CREATE TABLE IF NOT EXISTS order_for_labels (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
comanda_productie VARCHAR(15) NOT NULL,
|
||||
cod_articol VARCHAR(15) NULL,
|
||||
descr_com_prod VARCHAR(50) NOT NULL,
|
||||
cantitate INT(3) NOT NULL,
|
||||
com_achiz_client VARCHAR(25) NULL,
|
||||
nr_linie_com_client INT(3) NULL,
|
||||
customer_name VARCHAR(50) NULL,
|
||||
customer_article_number VARCHAR(25) NULL,
|
||||
open_for_order VARCHAR(25) NULL,
|
||||
line_number INT(3) NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
printed_labels INT(1) DEFAULT 0,
|
||||
data_livrare DATE NULL,
|
||||
dimensiune VARCHAR(20) NULL
|
||||
);
|
||||
"""
|
||||
cursor.execute(order_labels_query)
|
||||
print_success("Table 'order_for_labels' created successfully")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create order_for_labels table: {e}")
|
||||
return False
|
||||
|
||||
def create_warehouse_locations_table():
|
||||
"""Create warehouse_locations table"""
|
||||
print_step(4, "Creating Warehouse Locations Table")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
warehouse_query = """
|
||||
CREATE TABLE IF NOT EXISTS warehouse_locations (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
location_code VARCHAR(12) NOT NULL UNIQUE,
|
||||
size INT,
|
||||
description VARCHAR(250)
|
||||
);
|
||||
"""
|
||||
cursor.execute(warehouse_query)
|
||||
print_success("Table 'warehouse_locations' created successfully")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create warehouse_locations table: {e}")
|
||||
return False
|
||||
|
||||
def create_permissions_tables():
|
||||
"""Create permission management tables"""
|
||||
print_step(5, "Creating Permission Management Tables")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Create permissions table
|
||||
permissions_query = """
|
||||
CREATE TABLE IF NOT EXISTS permissions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
permission_key VARCHAR(255) UNIQUE NOT NULL,
|
||||
page VARCHAR(100) NOT NULL,
|
||||
page_name VARCHAR(255) NOT NULL,
|
||||
section VARCHAR(100) NOT NULL,
|
||||
section_name VARCHAR(255) NOT NULL,
|
||||
action VARCHAR(50) NOT NULL,
|
||||
action_name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
"""
|
||||
cursor.execute(permissions_query)
|
||||
print_success("Table 'permissions' created successfully")
|
||||
|
||||
# Create role_permissions table
|
||||
role_permissions_query = """
|
||||
CREATE TABLE IF NOT EXISTS role_permissions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
role_name VARCHAR(100) NOT NULL,
|
||||
permission_id INT NOT NULL,
|
||||
granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
granted_by VARCHAR(100),
|
||||
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_role_permission (role_name, permission_id)
|
||||
);
|
||||
"""
|
||||
cursor.execute(role_permissions_query)
|
||||
print_success("Table 'role_permissions' created successfully")
|
||||
|
||||
# Create role_hierarchy table
|
||||
role_hierarchy_query = """
|
||||
CREATE TABLE IF NOT EXISTS role_hierarchy (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
role_name VARCHAR(100) UNIQUE NOT NULL,
|
||||
role_display_name VARCHAR(255) NOT NULL,
|
||||
level INT NOT NULL,
|
||||
parent_role VARCHAR(100),
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
"""
|
||||
cursor.execute(role_hierarchy_query)
|
||||
print_success("Table 'role_hierarchy' created successfully")
|
||||
|
||||
# Create permission_audit_log table
|
||||
audit_log_query = """
|
||||
CREATE TABLE IF NOT EXISTS permission_audit_log (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
action VARCHAR(50) NOT NULL,
|
||||
role_name VARCHAR(100),
|
||||
permission_key VARCHAR(255),
|
||||
user_id VARCHAR(100),
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
details TEXT,
|
||||
ip_address VARCHAR(45)
|
||||
);
|
||||
"""
|
||||
cursor.execute(audit_log_query)
|
||||
print_success("Table 'permission_audit_log' created successfully")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create permissions tables: {e}")
|
||||
return False
|
||||
|
||||
def create_users_table_mariadb():
|
||||
"""Create users and roles tables in MariaDB and seed superadmin"""
|
||||
print_step(6, "Creating MariaDB Users and Roles Tables")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Create users table in MariaDB
|
||||
users_table_query = """
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(100) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(50) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
"""
|
||||
cursor.execute(users_table_query)
|
||||
print_success("Table 'users' created successfully")
|
||||
|
||||
# Create roles table in MariaDB
|
||||
roles_table_query = """
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) UNIQUE NOT NULL,
|
||||
access_level VARCHAR(50) NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
"""
|
||||
cursor.execute(roles_table_query)
|
||||
print_success("Table 'roles' created successfully")
|
||||
|
||||
# Insert superadmin role if not exists
|
||||
cursor.execute("SELECT COUNT(*) FROM roles WHERE name = %s", ('superadmin',))
|
||||
if cursor.fetchone()[0] == 0:
|
||||
cursor.execute("""
|
||||
INSERT INTO roles (name, access_level, description)
|
||||
VALUES (%s, %s, %s)
|
||||
""", ('superadmin', 'full', 'Full access to all app areas and functions'))
|
||||
print_success("Superadmin role created")
|
||||
|
||||
# Insert superadmin user if not exists
|
||||
cursor.execute("SELECT COUNT(*) FROM users WHERE username = %s", ('superadmin',))
|
||||
if cursor.fetchone()[0] == 0:
|
||||
cursor.execute("""
|
||||
INSERT INTO users (username, password, role)
|
||||
VALUES (%s, %s, %s)
|
||||
""", ('superadmin', 'superadmin123', 'superadmin'))
|
||||
print_success("Superadmin user created (username: superadmin, password: superadmin123)")
|
||||
else:
|
||||
print_success("Superadmin user already exists")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create users tables in MariaDB: {e}")
|
||||
return False
|
||||
|
||||
def create_sqlite_tables():
|
||||
"""Create SQLite tables for users and roles (legacy/backup)"""
|
||||
print_step(7, "Creating SQLite User and Role Tables (Backup)")
|
||||
|
||||
try:
|
||||
# Create instance folder if it doesn't exist
|
||||
instance_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance'))
|
||||
if not os.path.exists(instance_folder):
|
||||
os.makedirs(instance_folder)
|
||||
|
||||
db_path = os.path.join(instance_folder, 'users.db')
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Create users table
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
role TEXT NOT NULL
|
||||
)
|
||||
''')
|
||||
|
||||
# Insert superadmin user if not exists
|
||||
cursor.execute('''
|
||||
INSERT OR IGNORE INTO users (username, password, role)
|
||||
VALUES (?, ?, ?)
|
||||
''', ('superadmin', 'superadmin123', 'superadmin'))
|
||||
|
||||
# Create roles table
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
access_level TEXT NOT NULL,
|
||||
description TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
# Insert superadmin role if not exists
|
||||
cursor.execute('''
|
||||
INSERT OR IGNORE INTO roles (name, access_level, description)
|
||||
VALUES (?, ?, ?)
|
||||
''', ('superadmin', 'full', 'Full access to all app areas and functions'))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print_success("SQLite tables created and superadmin user initialized")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create SQLite tables: {e}")
|
||||
return False
|
||||
|
||||
def create_database_triggers():
|
||||
"""Create database triggers for automatic quantity calculations"""
|
||||
print_step(8, "Creating Database Triggers")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Drop existing triggers if they exist
|
||||
trigger_drops = [
|
||||
"DROP TRIGGER IF EXISTS increment_approved_quantity;",
|
||||
"DROP TRIGGER IF EXISTS increment_rejected_quantity;",
|
||||
"DROP TRIGGER IF EXISTS increment_approved_quantity_fg;",
|
||||
"DROP TRIGGER IF EXISTS increment_rejected_quantity_fg;"
|
||||
]
|
||||
|
||||
for drop_query in trigger_drops:
|
||||
cursor.execute(drop_query)
|
||||
|
||||
# Create trigger for scan1_orders approved quantity
|
||||
scan1_approved_trigger = """
|
||||
CREATE TRIGGER increment_approved_quantity
|
||||
AFTER INSERT ON scan1_orders
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.quality_code = 000 THEN
|
||||
UPDATE scan1_orders
|
||||
SET approved_quantity = approved_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
ELSE
|
||||
UPDATE scan1_orders
|
||||
SET rejected_quantity = rejected_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
END IF;
|
||||
END;
|
||||
"""
|
||||
cursor.execute(scan1_approved_trigger)
|
||||
print_success("Trigger 'increment_approved_quantity' created for scan1_orders")
|
||||
|
||||
# Create trigger for scanfg_orders approved quantity
|
||||
scanfg_approved_trigger = """
|
||||
CREATE TRIGGER increment_approved_quantity_fg
|
||||
AFTER INSERT ON scanfg_orders
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.quality_code = 000 THEN
|
||||
UPDATE scanfg_orders
|
||||
SET approved_quantity = approved_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
ELSE
|
||||
UPDATE scanfg_orders
|
||||
SET rejected_quantity = rejected_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
END IF;
|
||||
END;
|
||||
"""
|
||||
cursor.execute(scanfg_approved_trigger)
|
||||
print_success("Trigger 'increment_approved_quantity_fg' created for scanfg_orders")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to create database triggers: {e}")
|
||||
return False
|
||||
|
||||
def populate_permissions_data():
|
||||
"""Populate permissions and roles with default data"""
|
||||
print_step(9, "Populating Permissions and Roles Data")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Define all permissions
|
||||
permissions_data = [
|
||||
# Home page permissions
|
||||
('home.view', 'home', 'Home Page', 'navigation', 'Navigation', 'view', 'View Home Page', 'Access to home page'),
|
||||
|
||||
# Scan1 permissions
|
||||
('scan1.view', 'scan1', 'Scan1 Page', 'scanning', 'Scanning Operations', 'view', 'View Scan1', 'Access to scan1 page'),
|
||||
('scan1.scan', 'scan1', 'Scan1 Page', 'scanning', 'Scanning Operations', 'scan', 'Perform Scan1', 'Ability to perform scan1 operations'),
|
||||
('scan1.history', 'scan1', 'Scan1 Page', 'scanning', 'Scanning Operations', 'history', 'View Scan1 History', 'View scan1 operation history'),
|
||||
|
||||
# ScanFG permissions
|
||||
('scanfg.view', 'scanfg', 'ScanFG Page', 'scanning', 'Scanning Operations', 'view', 'View ScanFG', 'Access to scanfg page'),
|
||||
('scanfg.scan', 'scanfg', 'ScanFG Page', 'scanning', 'Scanning Operations', 'scan', 'Perform ScanFG', 'Ability to perform scanfg operations'),
|
||||
('scanfg.history', 'scanfg', 'ScanFG Page', 'scanning', 'Scanning Operations', 'history', 'View ScanFG History', 'View scanfg operation history'),
|
||||
|
||||
# Warehouse permissions
|
||||
('warehouse.view', 'warehouse', 'Warehouse Management', 'warehouse', 'Warehouse Operations', 'view', 'View Warehouse', 'Access to warehouse page'),
|
||||
('warehouse.manage_locations', 'warehouse', 'Warehouse Management', 'warehouse', 'Warehouse Operations', 'manage', 'Manage Locations', 'Add, edit, delete warehouse locations'),
|
||||
('warehouse.view_locations', 'warehouse', 'Warehouse Management', 'warehouse', 'Warehouse Operations', 'view_locations', 'View Locations', 'View warehouse locations'),
|
||||
|
||||
# Labels permissions
|
||||
('labels.view', 'labels', 'Label Management', 'labels', 'Label Operations', 'view', 'View Labels', 'Access to labels page'),
|
||||
('labels.print', 'labels', 'Label Management', 'labels', 'Label Operations', 'print', 'Print Labels', 'Print labels'),
|
||||
('labels.manage_orders', 'labels', 'Label Management', 'labels', 'Label Operations', 'manage', 'Manage Label Orders', 'Manage label orders'),
|
||||
|
||||
# Print Module permissions
|
||||
('print.view', 'print', 'Print Module', 'printing', 'Printing Operations', 'view', 'View Print Module', 'Access to print module'),
|
||||
('print.execute', 'print', 'Print Module', 'printing', 'Printing Operations', 'execute', 'Execute Print', 'Execute print operations'),
|
||||
('print.manage_queue', 'print', 'Print Module', 'printing', 'Printing Operations', 'manage_queue', 'Manage Print Queue', 'Manage print queue'),
|
||||
|
||||
# Settings permissions
|
||||
('settings.view', 'settings', 'Settings', 'system', 'System Management', 'view', 'View Settings', 'Access to settings page'),
|
||||
('settings.edit', 'settings', 'Settings', 'system', 'System Management', 'edit', 'Edit Settings', 'Modify application settings'),
|
||||
('settings.database', 'settings', 'Settings', 'system', 'System Management', 'database', 'Database Settings', 'Manage database settings'),
|
||||
|
||||
# User Management permissions
|
||||
('users.view', 'users', 'User Management', 'admin', 'Administration', 'view', 'View Users', 'View user list'),
|
||||
('users.create', 'users', 'User Management', 'admin', 'Administration', 'create', 'Create Users', 'Create new users'),
|
||||
('users.edit', 'users', 'User Management', 'admin', 'Administration', 'edit', 'Edit Users', 'Edit existing users'),
|
||||
('users.delete', 'users', 'User Management', 'admin', 'Administration', 'delete', 'Delete Users', 'Delete users'),
|
||||
|
||||
# Permission Management permissions
|
||||
('permissions.view', 'permissions', 'Permission Management', 'admin', 'Administration', 'view', 'View Permissions', 'View permissions'),
|
||||
('permissions.assign', 'permissions', 'Permission Management', 'admin', 'Administration', 'assign', 'Assign Permissions', 'Assign permissions to roles'),
|
||||
('permissions.audit', 'permissions', 'Permission Management', 'admin', 'Administration', 'audit', 'View Audit Log', 'View permission audit log'),
|
||||
]
|
||||
|
||||
# Insert permissions
|
||||
permission_insert_query = """
|
||||
INSERT IGNORE INTO permissions
|
||||
(permission_key, page, page_name, section, section_name, action, action_name, description)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
cursor.executemany(permission_insert_query, permissions_data)
|
||||
print_success(f"Inserted {len(permissions_data)} permissions")
|
||||
|
||||
# Define role hierarchy
|
||||
roles_data = [
|
||||
('superadmin', 'Super Administrator', 1, None, 'Full system access with all permissions'),
|
||||
('admin', 'Administrator', 2, 'superadmin', 'Administrative access with most permissions'),
|
||||
('manager', 'Manager', 3, 'admin', 'Management level access'),
|
||||
('quality_manager', 'Quality Manager', 4, 'manager', 'Quality control and scanning operations'),
|
||||
('warehouse_manager', 'Warehouse Manager', 4, 'manager', 'Warehouse operations and management'),
|
||||
('quality_worker', 'Quality Worker', 5, 'quality_manager', 'Basic quality scanning operations'),
|
||||
('warehouse_worker', 'Warehouse Worker', 5, 'warehouse_manager', 'Basic warehouse operations'),
|
||||
]
|
||||
|
||||
# Insert roles
|
||||
role_insert_query = """
|
||||
INSERT IGNORE INTO role_hierarchy
|
||||
(role_name, role_display_name, level, parent_role, description)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
cursor.executemany(role_insert_query, roles_data)
|
||||
print_success(f"Inserted {len(roles_data)} roles")
|
||||
|
||||
# Assign permissions to roles
|
||||
# Get all permission IDs
|
||||
cursor.execute("SELECT id, permission_key FROM permissions")
|
||||
permissions = {key: id for id, key in cursor.fetchall()}
|
||||
|
||||
# Define role-permission mappings
|
||||
role_permissions = {
|
||||
'superadmin': list(permissions.values()), # All permissions
|
||||
'admin': [pid for key, pid in permissions.items() if not key.startswith('permissions.audit')], # All except audit
|
||||
'manager': [permissions[key] for key in permissions.keys() if any(key.startswith(prefix) for prefix in ['home.', 'settings.view', 'users.view'])],
|
||||
'quality_manager': [permissions[key] for key in permissions.keys() if any(key.startswith(prefix) for prefix in ['home.', 'scan1.', 'scanfg.', 'labels.', 'print.'])],
|
||||
'warehouse_manager': [permissions[key] for key in permissions.keys() if any(key.startswith(prefix) for prefix in ['home.', 'warehouse.', 'labels.'])],
|
||||
'quality_worker': [permissions[key] for key in permissions.keys() if any(key.startswith(prefix) for prefix in ['home.', 'scan1.view', 'scan1.scan', 'scanfg.view', 'scanfg.scan'])],
|
||||
'warehouse_worker': [permissions[key] for key in permissions.keys() if any(key.startswith(prefix) for prefix in ['home.', 'warehouse.view', 'warehouse.view_locations'])],
|
||||
}
|
||||
|
||||
# Insert role permissions
|
||||
for role, permission_ids in role_permissions.items():
|
||||
for permission_id in permission_ids:
|
||||
cursor.execute("""
|
||||
INSERT IGNORE INTO role_permissions (role_name, permission_id)
|
||||
VALUES (%s, %s)
|
||||
""", (role, permission_id))
|
||||
|
||||
print_success("Role permissions assigned successfully")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to populate permissions data: {e}")
|
||||
return False
|
||||
|
||||
def update_external_config():
|
||||
"""Update external_server.conf with correct database settings"""
|
||||
print_step(10, "Updating External Server Configuration")
|
||||
|
||||
try:
|
||||
config_path = os.path.join(os.path.dirname(__file__), '../../instance/external_server.conf')
|
||||
|
||||
# Use environment variables if available (Docker), otherwise use defaults
|
||||
db_host = os.getenv('DB_HOST', 'localhost')
|
||||
db_port = os.getenv('DB_PORT', '3306')
|
||||
db_name = os.getenv('DB_NAME', 'trasabilitate')
|
||||
db_user = os.getenv('DB_USER', 'trasabilitate')
|
||||
db_password = os.getenv('DB_PASSWORD', 'Initial01!')
|
||||
|
||||
config_content = f"""server_domain={db_host}
|
||||
port={db_port}
|
||||
database_name={db_name}
|
||||
username={db_user}
|
||||
password={db_password}
|
||||
"""
|
||||
|
||||
# Create instance directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(config_path), exist_ok=True)
|
||||
|
||||
with open(config_path, 'w') as f:
|
||||
f.write(config_content)
|
||||
|
||||
print_success(f"External server configuration updated (host: {db_host})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to update external config: {e}")
|
||||
return False
|
||||
|
||||
def verify_database_setup():
|
||||
"""Verify that all tables were created successfully"""
|
||||
print_step(11, "Verifying Database Setup")
|
||||
|
||||
try:
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check MariaDB tables
|
||||
cursor.execute("SHOW TABLES")
|
||||
tables = [table[0] for table in cursor.fetchall()]
|
||||
|
||||
expected_tables = [
|
||||
'scan1_orders',
|
||||
'scanfg_orders',
|
||||
'order_for_labels',
|
||||
'warehouse_locations',
|
||||
'permissions',
|
||||
'role_permissions',
|
||||
'role_hierarchy',
|
||||
'permission_audit_log',
|
||||
'users',
|
||||
'roles'
|
||||
]
|
||||
|
||||
print("\n📊 MariaDB Tables Status:")
|
||||
for table in expected_tables:
|
||||
if table in tables:
|
||||
print_success(f"Table '{table}' exists")
|
||||
else:
|
||||
print_error(f"Table '{table}' missing")
|
||||
|
||||
# Check triggers
|
||||
cursor.execute("SHOW TRIGGERS")
|
||||
triggers = [trigger[0] for trigger in cursor.fetchall()]
|
||||
|
||||
expected_triggers = [
|
||||
'increment_approved_quantity',
|
||||
'increment_approved_quantity_fg'
|
||||
]
|
||||
|
||||
print("\n🔧 Database Triggers Status:")
|
||||
for trigger in expected_triggers:
|
||||
if trigger in triggers:
|
||||
print_success(f"Trigger '{trigger}' exists")
|
||||
else:
|
||||
print_error(f"Trigger '{trigger}' missing")
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
# Check SQLite database
|
||||
instance_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../instance'))
|
||||
sqlite_path = os.path.join(instance_folder, 'users.db')
|
||||
|
||||
if os.path.exists(sqlite_path):
|
||||
print_success("SQLite database 'users.db' exists")
|
||||
else:
|
||||
print_error("SQLite database 'users.db' missing")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print_error(f"Failed to verify database setup: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Main function to orchestrate the complete database setup"""
|
||||
print("🚀 Trasabilitate Application - Complete Database Setup")
|
||||
print(f"Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
steps = [
|
||||
test_database_connection,
|
||||
create_scan_tables,
|
||||
create_order_for_labels_table,
|
||||
create_warehouse_locations_table,
|
||||
create_permissions_tables,
|
||||
create_users_table_mariadb,
|
||||
create_sqlite_tables,
|
||||
create_database_triggers,
|
||||
populate_permissions_data,
|
||||
update_external_config,
|
||||
verify_database_setup
|
||||
]
|
||||
|
||||
success_count = 0
|
||||
|
||||
for step in steps:
|
||||
if step():
|
||||
success_count += 1
|
||||
else:
|
||||
print(f"\n❌ Setup failed at step: {step.__name__}")
|
||||
print("Please check the error messages above and resolve the issues.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("🎉 DATABASE SETUP COMPLETED SUCCESSFULLY!")
|
||||
print(f"{'='*60}")
|
||||
print(f"✅ All {success_count} steps completed successfully")
|
||||
print(f"📅 Completed at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("\n📋 Setup Summary:")
|
||||
print(" • MariaDB tables created with triggers")
|
||||
print(" • SQLite user database initialized")
|
||||
print(" • Permissions system fully configured")
|
||||
print(" • Default superadmin user created (username: superadmin, password: superadmin123)")
|
||||
print(" • Configuration files updated")
|
||||
print("\n🚀 Your application is ready to run!")
|
||||
print(" Run: python3 run.py")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -4,47 +4,7 @@ class User(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
||||
password = db.Column(db.String(120), nullable=False)
|
||||
role = db.Column(db.String(20), nullable=False) # Role: superadmin, admin, manager, worker
|
||||
modules = db.Column(db.Text, nullable=True) # JSON string of assigned modules: ["quality", "warehouse"]
|
||||
role = db.Column(db.String(20), nullable=False) # Role: superadmin, administrator, quality, warehouse, scan
|
||||
|
||||
def __repr__(self):
|
||||
return f'<User {self.username}>'
|
||||
|
||||
def get_modules(self):
|
||||
"""Get user's assigned modules as a list"""
|
||||
if not self.modules:
|
||||
return []
|
||||
try:
|
||||
import json
|
||||
return json.loads(self.modules)
|
||||
except:
|
||||
return []
|
||||
|
||||
def set_modules(self, module_list):
|
||||
"""Set user's assigned modules from a list"""
|
||||
if not module_list:
|
||||
self.modules = None
|
||||
else:
|
||||
import json
|
||||
self.modules = json.dumps(module_list)
|
||||
|
||||
def add_module(self, module):
|
||||
"""Add a module to user's assignments"""
|
||||
current_modules = self.get_modules()
|
||||
if module not in current_modules:
|
||||
current_modules.append(module)
|
||||
self.set_modules(current_modules)
|
||||
|
||||
def remove_module(self, module):
|
||||
"""Remove a module from user's assignments"""
|
||||
current_modules = self.get_modules()
|
||||
if module in current_modules:
|
||||
current_modules.remove(module)
|
||||
self.set_modules(current_modules)
|
||||
|
||||
def has_module(self, module):
|
||||
"""Check if user has access to a specific module"""
|
||||
# Superadmin and admin have access to all modules
|
||||
if self.role in ['superadmin', 'admin']:
|
||||
return True
|
||||
return module in self.get_modules()
|
||||
return f'<User {self.username}>'
|
||||
@@ -1,240 +0,0 @@
|
||||
"""
|
||||
Simplified 4-Tier Role-Based Access Control System
|
||||
Clear hierarchy: Superadmin → Admin → Manager → Worker
|
||||
Module-based permissions: Quality, Labels, Warehouse
|
||||
"""
|
||||
|
||||
# APPLICATION MODULES
|
||||
MODULES = {
|
||||
'quality': {
|
||||
'name': 'Quality Control',
|
||||
'scan_pages': ['quality', 'fg_quality'],
|
||||
'management_pages': ['quality_reports', 'quality_settings'],
|
||||
'worker_access': ['scan_only'] # Workers can only scan, no reports
|
||||
},
|
||||
'labels': {
|
||||
'name': 'Label Management',
|
||||
'scan_pages': ['label_scan'],
|
||||
'management_pages': ['label_creation', 'label_reports'],
|
||||
'worker_access': ['scan_only']
|
||||
},
|
||||
'warehouse': {
|
||||
'name': 'Warehouse Management',
|
||||
'scan_pages': ['move_orders'],
|
||||
'management_pages': ['create_locations', 'warehouse_reports', 'inventory_management'],
|
||||
'worker_access': ['move_orders_only'] # Workers can move orders but not create locations
|
||||
},
|
||||
'daily_mirror': {
|
||||
'name': 'Daily Mirror',
|
||||
'scan_pages': [], # No scanning, purely reporting/analytics
|
||||
'management_pages': ['daily_mirror_main', 'daily_mirror_report', 'daily_mirror_history', 'daily_mirror_analytics'],
|
||||
'worker_access': ['view_only'], # Workers can view daily reports but cannot generate or export
|
||||
'description': 'Business Intelligence and Production Reporting Module'
|
||||
}
|
||||
}
|
||||
|
||||
# 4-TIER ROLE STRUCTURE
|
||||
ROLES = {
|
||||
'superadmin': {
|
||||
'name': 'Super Administrator',
|
||||
'level': 100,
|
||||
'description': 'Full system access - complete control over all modules and system settings',
|
||||
'access': {
|
||||
'all_modules': True,
|
||||
'all_pages': True,
|
||||
'restricted_pages': [] # No restrictions
|
||||
}
|
||||
},
|
||||
'admin': {
|
||||
'name': 'Administrator',
|
||||
'level': 90,
|
||||
'description': 'Full app access except role permissions and extension download',
|
||||
'access': {
|
||||
'all_modules': True,
|
||||
'all_pages': True,
|
||||
'restricted_pages': ['role_permissions', 'download_extension']
|
||||
}
|
||||
},
|
||||
'manager': {
|
||||
'name': 'Manager',
|
||||
'level': 70,
|
||||
'description': 'Complete module access - can manage one or more modules (quality/labels/warehouse)',
|
||||
'access': {
|
||||
'all_modules': False, # Only assigned modules
|
||||
'module_access': 'full', # Full access to assigned modules
|
||||
'can_cumulate': True, # Can have multiple modules
|
||||
'restricted_pages': ['role_permissions', 'download_extension', 'system_settings']
|
||||
}
|
||||
},
|
||||
'worker': {
|
||||
'name': 'Worker',
|
||||
'level': 50,
|
||||
'description': 'Limited module access - can perform basic operations in assigned modules',
|
||||
'access': {
|
||||
'all_modules': False, # Only assigned modules
|
||||
'module_access': 'limited', # Limited access (scan pages only)
|
||||
'can_cumulate': True, # Can have multiple modules
|
||||
'restricted_pages': ['role_permissions', 'download_extension', 'system_settings', 'reports']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# PAGE ACCESS RULES
|
||||
PAGE_ACCESS = {
|
||||
# System pages accessible by role level
|
||||
'dashboard': {'min_level': 50, 'modules': []},
|
||||
'settings': {'min_level': 90, 'modules': []},
|
||||
'role_permissions': {'min_level': 100, 'modules': []}, # Superadmin only
|
||||
'download_extension': {'min_level': 100, 'modules': []}, # Superadmin only
|
||||
|
||||
# Quality module pages
|
||||
'quality': {'min_level': 50, 'modules': ['quality']},
|
||||
'fg_quality': {'min_level': 50, 'modules': ['quality']},
|
||||
'quality_reports': {'min_level': 70, 'modules': ['quality']}, # Manager+ only
|
||||
'reports': {'min_level': 70, 'modules': ['quality']}, # Manager+ only for quality reports
|
||||
|
||||
# Warehouse module pages
|
||||
'warehouse': {'min_level': 50, 'modules': ['warehouse']},
|
||||
'move_orders': {'min_level': 50, 'modules': ['warehouse']},
|
||||
'create_locations': {'min_level': 70, 'modules': ['warehouse']}, # Manager+ only
|
||||
'warehouse_reports': {'min_level': 70, 'modules': ['warehouse']}, # Manager+ only
|
||||
|
||||
# Labels module pages
|
||||
'labels': {'min_level': 50, 'modules': ['labels']},
|
||||
'label_scan': {'min_level': 50, 'modules': ['labels']},
|
||||
'label_creation': {'min_level': 70, 'modules': ['labels']}, # Manager+ only
|
||||
'label_reports': {'min_level': 70, 'modules': ['labels']}, # Manager+ only
|
||||
|
||||
# Daily Mirror module pages
|
||||
'daily_mirror_main': {'min_level': 70, 'modules': ['daily_mirror']}, # Manager+ only
|
||||
'daily_mirror_report': {'min_level': 70, 'modules': ['daily_mirror']}, # Manager+ only
|
||||
'daily_mirror_history': {'min_level': 70, 'modules': ['daily_mirror']}, # Manager+ only
|
||||
'daily_mirror_analytics': {'min_level': 90, 'modules': ['daily_mirror']}, # Admin+ only for advanced analytics
|
||||
'daily_mirror': {'min_level': 70, 'modules': ['daily_mirror']} # Legacy route support
|
||||
}
|
||||
|
||||
def check_access(user_role, user_modules, page):
|
||||
"""
|
||||
Simple access check for the 4-tier system
|
||||
|
||||
Args:
|
||||
user_role (str): User's role (superadmin, admin, manager, worker)
|
||||
user_modules (list): User's assigned modules ['quality', 'warehouse']
|
||||
page (str): Page being accessed
|
||||
|
||||
Returns:
|
||||
bool: True if access granted, False otherwise
|
||||
"""
|
||||
if user_role not in ROLES:
|
||||
return False
|
||||
|
||||
user_level = ROLES[user_role]['level']
|
||||
|
||||
# Check if page exists in our access rules
|
||||
if page not in PAGE_ACCESS:
|
||||
return False
|
||||
|
||||
page_config = PAGE_ACCESS[page]
|
||||
|
||||
# Check minimum level requirement
|
||||
if user_level < page_config['min_level']:
|
||||
return False
|
||||
|
||||
# Check restricted pages for this role
|
||||
if page in ROLES[user_role]['access']['restricted_pages']:
|
||||
return False
|
||||
|
||||
# Check module requirements
|
||||
required_modules = page_config['modules']
|
||||
if required_modules:
|
||||
# Page requires specific modules
|
||||
# Superadmin and admin have access to all modules by default
|
||||
if ROLES[user_role]['access']['all_modules']:
|
||||
return True
|
||||
# Other roles need to have the required module assigned
|
||||
if not any(module in user_modules for module in required_modules):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_user_accessible_pages(user_role, user_modules):
|
||||
"""
|
||||
Get list of pages accessible to a user
|
||||
|
||||
Args:
|
||||
user_role (str): User's role
|
||||
user_modules (list): User's assigned modules
|
||||
|
||||
Returns:
|
||||
list: List of accessible page names
|
||||
"""
|
||||
accessible_pages = []
|
||||
|
||||
for page in PAGE_ACCESS.keys():
|
||||
if check_access(user_role, user_modules, page):
|
||||
accessible_pages.append(page)
|
||||
|
||||
return accessible_pages
|
||||
|
||||
def validate_user_modules(user_role, user_modules):
|
||||
"""
|
||||
Validate that user's module assignment is valid for their role
|
||||
|
||||
Args:
|
||||
user_role (str): User's role
|
||||
user_modules (list): User's assigned modules
|
||||
|
||||
Returns:
|
||||
tuple: (is_valid, error_message)
|
||||
"""
|
||||
if user_role not in ROLES:
|
||||
return False, "Invalid role"
|
||||
|
||||
role_config = ROLES[user_role]
|
||||
|
||||
# Superadmin and admin have access to all modules by default
|
||||
if role_config['access']['all_modules']:
|
||||
return True, ""
|
||||
|
||||
# Manager can have multiple modules
|
||||
if user_role == 'manager':
|
||||
if not user_modules:
|
||||
return False, "Managers must have at least one module assigned"
|
||||
valid_modules = list(MODULES.keys())
|
||||
for module in user_modules:
|
||||
if module not in valid_modules:
|
||||
return False, f"Invalid module: {module}"
|
||||
return True, ""
|
||||
|
||||
# Worker can have multiple modules now
|
||||
if user_role == 'worker':
|
||||
if not user_modules:
|
||||
return False, "Workers must have at least one module assigned"
|
||||
valid_modules = list(MODULES.keys())
|
||||
for module in user_modules:
|
||||
if module not in valid_modules:
|
||||
return False, f"Invalid module: {module}"
|
||||
return True, ""
|
||||
|
||||
return True, ""
|
||||
|
||||
def get_role_description(role):
|
||||
"""Get human-readable role description"""
|
||||
return ROLES.get(role, {}).get('description', 'Unknown role')
|
||||
|
||||
def get_available_modules():
|
||||
"""Get list of available modules"""
|
||||
return list(MODULES.keys())
|
||||
|
||||
def can_access_reports(user_role, user_modules, module):
|
||||
"""
|
||||
Check if user can access reports for a specific module
|
||||
Worker level users cannot access reports
|
||||
"""
|
||||
if user_role == 'worker':
|
||||
return False
|
||||
|
||||
if module in user_modules or ROLES[user_role]['access']['all_modules']:
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -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,
|
||||
com_achiz_client, nr_linie_com_client, customer_name,
|
||||
data_livrare, dimensiune, 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
|
||||
printed_labels, created_at, updated_at
|
||||
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,
|
||||
com_achiz_client, nr_linie_com_client, customer_name,
|
||||
data_livrare, dimensiune, 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],
|
||||
'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],
|
||||
'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': row[13],
|
||||
'data_livrare': row[14] or '-',
|
||||
'dimensiune': row[15] or '-'
|
||||
'created_at': row[14],
|
||||
'updated_at': row[15]
|
||||
})
|
||||
else:
|
||||
orders.append({
|
||||
@@ -82,18 +82,17 @@ def get_unprinted_orders_data(limit=100):
|
||||
'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],
|
||||
# Add default values for missing columns
|
||||
'data_livrare': '-',
|
||||
'dimensiune': '-',
|
||||
'printed_labels': 0
|
||||
'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]
|
||||
})
|
||||
|
||||
conn.close()
|
||||
|
||||
1308
py_app/app/routes.py
@@ -172,41 +172,37 @@ def settings_handler():
|
||||
flash('Access denied: Superadmin only.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
# Get users from external MariaDB database with modules (same logic as user_management_simple)
|
||||
# Get users from external MariaDB database
|
||||
users = []
|
||||
try:
|
||||
conn = get_external_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Check if users table exists and get users with modules
|
||||
cursor.execute("SHOW TABLES LIKE 'users'")
|
||||
if cursor.fetchone():
|
||||
cursor.execute("SELECT id, username, role, modules FROM users")
|
||||
for row in cursor.fetchall():
|
||||
user_data = {
|
||||
'id': row[0],
|
||||
'username': row[1],
|
||||
'role': row[2],
|
||||
'modules': row[3] if len(row) > 3 else None
|
||||
}
|
||||
# Create a mock user object with get_modules method
|
||||
class MockUser:
|
||||
def __init__(self, data):
|
||||
self.id = data['id']
|
||||
self.username = data['username']
|
||||
self.role = data['role']
|
||||
self.modules = data['modules']
|
||||
|
||||
def get_modules(self):
|
||||
if not self.modules:
|
||||
return []
|
||||
try:
|
||||
import json
|
||||
return json.loads(self.modules)
|
||||
except:
|
||||
return []
|
||||
|
||||
users.append(MockUser(user_data))
|
||||
# Create users table if it doesn't exist
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(50) NOT NULL,
|
||||
email VARCHAR(255)
|
||||
)
|
||||
''')
|
||||
|
||||
# Get all users from external database
|
||||
cursor.execute("SELECT id, username, password, role, email FROM users")
|
||||
users_data = cursor.fetchall()
|
||||
|
||||
# Convert to list of dictionaries for template compatibility
|
||||
users = []
|
||||
for user_data in users_data:
|
||||
users.append({
|
||||
'id': user_data[0],
|
||||
'username': user_data[1],
|
||||
'password': user_data[2],
|
||||
'role': user_data[3],
|
||||
'email': user_data[4] if len(user_data) > 4 else None
|
||||
})
|
||||
|
||||
conn.close()
|
||||
|
||||
|
||||
@@ -146,111 +146,4 @@ body.dark-mode header {
|
||||
|
||||
body.dark-mode .user-info {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
FLOATING BUTTONS
|
||||
========================================================================== */
|
||||
|
||||
/* Floating Help Button */
|
||||
.floating-help-btn {
|
||||
position: fixed;
|
||||
top: 80px; /* Position below the header */
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #17a2b8, #138496);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.floating-help-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(0,0,0,0.25);
|
||||
background: linear-gradient(135deg, #138496, #0f6674);
|
||||
}
|
||||
|
||||
.floating-help-btn a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.floating-help-btn a:hover {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Floating Back Button */
|
||||
.floating-back-btn {
|
||||
position: fixed;
|
||||
top: 80px; /* Position below the header */
|
||||
left: 20px;
|
||||
z-index: 1000;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #6c757d, #545b62);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.floating-back-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(0,0,0,0.25);
|
||||
background: linear-gradient(135deg, #545b62, #495057);
|
||||
}
|
||||
|
||||
.floating-back-btn a,
|
||||
.floating-back-btn button {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.floating-back-btn a:hover,
|
||||
.floating-back-btn button:hover {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Dark mode styles for floating buttons */
|
||||
body.dark-mode .floating-help-btn {
|
||||
background: linear-gradient(135deg, #0dcaf0, #0aa2c0);
|
||||
}
|
||||
|
||||
body.dark-mode .floating-help-btn:hover {
|
||||
background: linear-gradient(135deg, #0aa2c0, #087990);
|
||||
}
|
||||
|
||||
body.dark-mode .floating-back-btn {
|
||||
background: linear-gradient(135deg, #495057, #343a40);
|
||||
}
|
||||
|
||||
body.dark-mode .floating-back-btn:hover {
|
||||
background: linear-gradient(135deg, #343a40, #212529);
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
/* Daily Mirror Tune Pages - Modal Styles */
|
||||
/* Fixes for editable modals across tune/production, tune/orders, and tune/delivery pages */
|
||||
|
||||
/* Force modal width to be extra wide (95% of viewport width) */
|
||||
#editModal .modal-dialog {
|
||||
max-width: 95vw !important;
|
||||
}
|
||||
|
||||
/* Modal footer button spacing and sizing */
|
||||
#editModal .modal-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#editModal .modal-footer .btn {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
#editModal .modal-footer .btn-danger {
|
||||
min-width: 150px;
|
||||
background-color: #dc3545 !important;
|
||||
border-color: #dc3545 !important;
|
||||
}
|
||||
|
||||
#editModal .modal-footer .btn-danger:hover {
|
||||
background-color: #bb2d3b !important;
|
||||
border-color: #b02a37 !important;
|
||||
}
|
||||
|
||||
#editModal .modal-footer .btn-primary {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
#editModal .modal-footer .btn-secondary {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Force Bootstrap modal to have proper z-index */
|
||||
#editModal.modal {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
#editModal .modal-backdrop {
|
||||
z-index: 9998 !important;
|
||||
}
|
||||
|
||||
/* Ensure modal dialog is interactive */
|
||||
#editModal .modal-dialog {
|
||||
pointer-events: auto !important;
|
||||
z-index: 10000 !important;
|
||||
}
|
||||
|
||||
#editModal .modal-content {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* Make all inputs in the modal fully interactive */
|
||||
#editModal .form-control:not([readonly]),
|
||||
#editModal .form-select:not([readonly]),
|
||||
#editModal input:not([readonly]):not([type="hidden"]),
|
||||
#editModal select:not([readonly]),
|
||||
#editModal textarea:not([readonly]) {
|
||||
pointer-events: auto !important;
|
||||
user-select: text !important;
|
||||
cursor: text !important;
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
opacity: 1 !important;
|
||||
-webkit-user-select: text !important;
|
||||
-moz-user-select: text !important;
|
||||
-ms-user-select: text !important;
|
||||
}
|
||||
|
||||
#editModal .form-control:focus:not([readonly]),
|
||||
#editModal input:focus:not([readonly]),
|
||||
#editModal select:focus:not([readonly]),
|
||||
#editModal textarea:focus:not([readonly]) {
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
border-color: #007bff !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25) !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
/* Dark mode specific overrides for modal inputs */
|
||||
body.dark-mode #editModal .form-control:not([readonly]),
|
||||
body.dark-mode #editModal input:not([readonly]):not([type="hidden"]),
|
||||
body.dark-mode #editModal select:not([readonly]),
|
||||
body.dark-mode #editModal textarea:not([readonly]) {
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
body.dark-mode #editModal .form-control:focus:not([readonly]),
|
||||
body.dark-mode #editModal input:focus:not([readonly]),
|
||||
body.dark-mode #editModal select:focus:not([readonly]),
|
||||
body.dark-mode #editModal textarea:focus:not([readonly]) {
|
||||
background-color: #ffffff !important;
|
||||
color: #000000 !important;
|
||||
border-color: #007bff !important;
|
||||
}
|
||||
|
||||
/* Readonly fields should still look readonly */
|
||||
#editModal .form-control[readonly],
|
||||
#editModal input[readonly] {
|
||||
background-color: #e9ecef !important;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
body.dark-mode #editModal .form-control[readonly],
|
||||
body.dark-mode #editModal input[readonly] {
|
||||
background-color: #6c757d !important;
|
||||
color: #e2e8f0 !important;
|
||||
}
|
||||
|
||||
/* Dark mode styles for cards and tables */
|
||||
body.dark-mode .card {
|
||||
background-color: #2d3748;
|
||||
color: #e2e8f0;
|
||||
border: 1px solid #4a5568;
|
||||
}
|
||||
|
||||
body.dark-mode .card-header {
|
||||
background-color: #4a5568;
|
||||
border-bottom: 1px solid #6b7280;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .form-control {
|
||||
background-color: #4a5568;
|
||||
border-color: #6b7280;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .form-control:focus {
|
||||
background-color: #4a5568;
|
||||
border-color: #007bff;
|
||||
color: #e2e8f0;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
||||
body.dark-mode .table {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .table-striped tbody tr:nth-of-type(odd) {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
body.dark-mode .table-hover tbody tr:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
body.dark-mode .modal-content {
|
||||
background-color: #2d3748;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-header {
|
||||
border-bottom: 1px solid #4a5568;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-footer {
|
||||
border-top: 1px solid #4a5568;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-secondary {
|
||||
background-color: #4a5568;
|
||||
border-color: #6b7280;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-secondary:hover {
|
||||
background-color: #6b7280;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-close {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
/* Table and button styling */
|
||||
.table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.btn-action {
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0.1rem;
|
||||
}
|
||||
|
||||
/* Editable field highlighting */
|
||||
.editable {
|
||||
background-color: #fff3cd;
|
||||
border: 1px dashed #ffc107;
|
||||
}
|
||||
|
||||
body.dark-mode .editable {
|
||||
background-color: #2d2d00;
|
||||
border: 1px dashed #ffc107;
|
||||
}
|
||||
|
||||
/* Compact table styling */
|
||||
.table-sm th,
|
||||
.table-sm td {
|
||||
padding: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Action button styling */
|
||||
.btn-sm {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Pagination styling */
|
||||
.pagination {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.page-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.dark-mode .pagination .page-link {
|
||||
background-color: #4a5568;
|
||||
border: 1px solid #6b7280;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .pagination .page-link:hover {
|
||||
background-color: #374151;
|
||||
border-color: #6b7280;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .pagination .page-item.active .page-link {
|
||||
background-color: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Additional dark mode styles */
|
||||
body.dark-mode .container-fluid {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .text-muted {
|
||||
color: #a0aec0 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .table-dark th {
|
||||
background-color: #1a202c;
|
||||
color: #e2e8f0;
|
||||
border-color: #4a5568;
|
||||
}
|
||||
|
||||
body.dark-mode .table-striped > tbody > tr:nth-of-type(odd) > td {
|
||||
background-color: #374151;
|
||||
}
|
||||
|
||||
body.dark-mode .table-hover > tbody > tr:hover > td {
|
||||
background-color: #4a5568;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.table-responsive {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.375rem 0.5rem;
|
||||
}
|
||||
}
|
||||
@@ -1,807 +0,0 @@
|
||||
/* ==========================================================================
|
||||
PRINT MODULE CSS - Dedicated styles for Labels/Printing Module
|
||||
==========================================================================
|
||||
|
||||
This file contains all CSS for the printing module pages:
|
||||
- print_module.html (main printing interface)
|
||||
- print_lost_labels.html (lost labels printing)
|
||||
- main_page_etichete.html (labels main page)
|
||||
- upload_data.html (upload orders)
|
||||
- view_orders.html (view orders)
|
||||
|
||||
========================================================================== */
|
||||
|
||||
/* ==========================================================================
|
||||
LABEL PREVIEW STYLES
|
||||
========================================================================== */
|
||||
|
||||
#label-preview {
|
||||
background: #fafafa;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Label content rectangle styling */
|
||||
#label-content {
|
||||
position: absolute;
|
||||
top: 65.7px;
|
||||
left: 11.34px;
|
||||
width: 227.4px;
|
||||
height: 321.3px;
|
||||
border: 1px solid #ddd;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* Barcode frame styling */
|
||||
#barcode-frame {
|
||||
position: absolute;
|
||||
top: 387px;
|
||||
left: 50%;
|
||||
transform: translateX(calc(-50% - 20px));
|
||||
width: 220px;
|
||||
max-width: 220px;
|
||||
height: 50px;
|
||||
background: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#barcode-display {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
#barcode-text {
|
||||
font-size: 8px;
|
||||
font-family: 'Courier New', monospace;
|
||||
margin-top: 2px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Vertical barcode frame styling */
|
||||
#vertical-barcode-frame {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 270px;
|
||||
width: 321.3px;
|
||||
height: 40px;
|
||||
background: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: rotate(90deg);
|
||||
transform-origin: left center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#vertical-barcode-display {
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
#vertical-barcode-text {
|
||||
position: absolute;
|
||||
bottom: -15px;
|
||||
font-size: 7px;
|
||||
font-family: 'Courier New', monospace;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Allow JsBarcode to control SVG colors naturally - removed forced black styling */
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT MODULE TABLE STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* Enhanced table styling for print module tables */
|
||||
.card.scan-table-card table.print-module-table.scan-table thead th {
|
||||
border-bottom: 2px solid var(--print-table-border) !important;
|
||||
background-color: var(--print-table-header-bg) !important;
|
||||
color: var(--print-table-header-text) !important;
|
||||
padding: 0.25rem 0.4rem !important;
|
||||
text-align: left !important;
|
||||
font-weight: 600 !important;
|
||||
font-size: 10px !important;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.card.scan-table-card table.print-module-table.scan-table {
|
||||
width: 100% !important;
|
||||
border-collapse: collapse !important;
|
||||
background-color: var(--print-table-body-bg) !important;
|
||||
}
|
||||
|
||||
.card.scan-table-card table.print-module-table.scan-table tbody tr:hover td {
|
||||
background-color: var(--print-table-hover) !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.card.scan-table-card table.print-module-table.scan-table tbody td {
|
||||
background-color: var(--print-table-body-bg) !important;
|
||||
color: var(--print-table-body-text) !important;
|
||||
border: 1px solid var(--print-table-border) !important;
|
||||
padding: 0.25rem 0.4rem !important;
|
||||
}
|
||||
|
||||
.card.scan-table-card table.print-module-table.scan-table tbody tr.selected td {
|
||||
background-color: var(--print-table-selected) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
VIEW ORDERS TABLE STYLES (for print_lost_labels.html)
|
||||
========================================================================== */
|
||||
|
||||
table.view-orders-table.scan-table {
|
||||
margin: 0 !important;
|
||||
border-spacing: 0 !important;
|
||||
border-collapse: collapse !important;
|
||||
width: 100% !important;
|
||||
table-layout: fixed !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
table.view-orders-table.scan-table thead th {
|
||||
height: 85px !important;
|
||||
min-height: 85px !important;
|
||||
max-height: 85px !important;
|
||||
vertical-align: middle !important;
|
||||
text-align: center !important;
|
||||
white-space: normal !important;
|
||||
word-wrap: break-word !important;
|
||||
line-height: 1.3 !important;
|
||||
padding: 6px 3px !important;
|
||||
font-size: 11px !important;
|
||||
background-color: var(--print-table-header-bg) !important;
|
||||
color: var(--print-table-header-text) !important;
|
||||
font-weight: bold !important;
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0 !important;
|
||||
overflow: visible !important;
|
||||
box-sizing: border-box !important;
|
||||
border: 1px solid var(--print-table-border) !important;
|
||||
text-overflow: clip !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
table.view-orders-table.scan-table tbody td {
|
||||
padding: 4px 2px !important;
|
||||
font-size: 10px !important;
|
||||
text-align: center !important;
|
||||
border: 1px solid var(--print-table-border) !important;
|
||||
background-color: var(--print-table-body-bg) !important;
|
||||
color: var(--print-table-body-text) !important;
|
||||
white-space: nowrap !important;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
/* Column width definitions for view orders table */
|
||||
table.view-orders-table.scan-table td:nth-child(1) { width: 50px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(2) { width: 80px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(3) { width: 80px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(4) { width: 150px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(5) { width: 70px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(6) { width: 80px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(7) { width: 75px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(8) { width: 90px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(9) { width: 70px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(10) { width: 100px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(11) { width: 90px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(12) { width: 70px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(13) { width: 50px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(14) { width: 70px !important; }
|
||||
table.view-orders-table.scan-table td:nth-child(15) { width: 100px !important; }
|
||||
|
||||
table.view-orders-table.scan-table tbody tr:hover td {
|
||||
background-color: var(--print-table-hover) !important;
|
||||
}
|
||||
|
||||
table.view-orders-table.scan-table tbody tr.selected td {
|
||||
background-color: var(--print-table-selected) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* Remove unwanted spacing */
|
||||
.report-table-card > * {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.report-table-container {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT MODULE LAYOUT STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* Scan container layout */
|
||||
.scan-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* Label preview card styling */
|
||||
.card.scan-form-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
min-height: 700px;
|
||||
width: 330px;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* Data preview card styling */
|
||||
.card.scan-table-card {
|
||||
min-height: 700px;
|
||||
width: calc(100% - 350px);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* View Orders and Upload Orders page specific layout - 25/75 split */
|
||||
.card.report-form-card,
|
||||
.card.scan-form-card {
|
||||
min-height: 700px;
|
||||
width: 25%;
|
||||
flex-shrink: 0;
|
||||
padding: 15px;
|
||||
margin-bottom: 0; /* Remove bottom margin for horizontal layout */
|
||||
}
|
||||
|
||||
.card.report-table-card,
|
||||
.card.scan-table-card {
|
||||
min-height: 700px;
|
||||
width: 75%;
|
||||
margin: 0;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* Upload Orders specific table styling */
|
||||
.card.scan-table-card table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Ensure proper scroll behavior for upload preview */
|
||||
.card.scan-table-card[style*="overflow-y: auto"] {
|
||||
/* Maintain scroll functionality while keeping consistent height */
|
||||
max-height: 700px;
|
||||
}
|
||||
|
||||
/* Label view title */
|
||||
.label-view-title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 0 0 15px 0;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
SEARCH AND FORM STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* Search card styling */
|
||||
.search-card {
|
||||
margin-bottom: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.search-field {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.quantity-field {
|
||||
width: 100px;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.search-result-table {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
BUTTON STYLES
|
||||
========================================================================== */
|
||||
|
||||
.print-btn {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.print-btn:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.print-btn:disabled {
|
||||
background-color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
REPORT TABLE CONTAINER STYLES
|
||||
========================================================================== */
|
||||
|
||||
.report-table-card h3 {
|
||||
margin: 0 0 15px 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.report-table-card {
|
||||
padding: 15px !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT MODULE SPECIFIC LAYOUT ADJUSTMENTS
|
||||
========================================================================== */
|
||||
|
||||
/* For print_lost_labels.html - Two-column layout */
|
||||
.scan-container.lost-labels {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.scan-container.lost-labels .search-card {
|
||||
width: 100%;
|
||||
max-height: 100px;
|
||||
min-height: 70px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.scan-container.lost-labels .row-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 24px;
|
||||
width: 100%;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT OPTIONS STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* Print method selection */
|
||||
.print-method-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.print-method-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.form-check {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* Printer selection styling */
|
||||
#qztray-printer-selection {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#qztray-printer-selection label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 3px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#qztray-printer-select {
|
||||
font-size: 11px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
/* Print button styling */
|
||||
#print-label-btn {
|
||||
font-size: 13px;
|
||||
padding: 8px 24px;
|
||||
border-radius: 5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* QZ Tray info section */
|
||||
#qztray-info {
|
||||
width: 100%;
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
#qztray-info .info-box {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#qztray-info .info-text {
|
||||
font-size: 10px;
|
||||
color: #495057;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
#qztray-info .download-link {
|
||||
font-size: 10px;
|
||||
padding: 4px 16px;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
BADGE AND STATUS STYLES
|
||||
========================================================================== */
|
||||
|
||||
.badge {
|
||||
font-size: 9px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-danger {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background-color: #ffc107;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
/* Status indicators */
|
||||
#qztray-status {
|
||||
font-size: 9px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
RESPONSIVE DESIGN
|
||||
========================================================================== */
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.scan-container {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.card.scan-form-card {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card.scan-table-card {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* View Orders and Upload Orders page responsive */
|
||||
.card.report-form-card,
|
||||
.card.scan-form-card {
|
||||
width: 100%;
|
||||
margin-bottom: 24px; /* Restore bottom margin for stacked layout */
|
||||
}
|
||||
|
||||
.card.report-table-card,
|
||||
.card.scan-table-card {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) and (min-width: 769px) {
|
||||
/* Tablet view - adjust proportions for better fit */
|
||||
.card.report-form-card,
|
||||
.card.scan-form-card {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.card.report-table-card,
|
||||
.card.scan-table-card {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.label-view-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#label-preview {
|
||||
width: 280px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#label-content {
|
||||
width: 200px;
|
||||
height: 290px;
|
||||
}
|
||||
|
||||
.search-field {
|
||||
max-width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
THEME SUPPORT (Light/Dark Mode)
|
||||
========================================================================== */
|
||||
|
||||
/* CSS Custom Properties for Theme Support */
|
||||
:root {
|
||||
/* Light mode colors (default) */
|
||||
--print-table-header-bg: #e9ecef;
|
||||
--print-table-header-text: #000;
|
||||
--print-table-body-bg: #fff;
|
||||
--print-table-body-text: #000;
|
||||
--print-table-border: #ddd;
|
||||
--print-table-hover: #f8f9fa;
|
||||
--print-table-selected: #007bff;
|
||||
--print-card-bg: #fff;
|
||||
--print-card-border: #ddd;
|
||||
--print-search-field-bg: #fff;
|
||||
--print-search-field-text: #000;
|
||||
--print-search-field-border: #ddd;
|
||||
}
|
||||
|
||||
/* Light mode theme variables */
|
||||
body.light-mode {
|
||||
--print-table-header-bg: #e9ecef;
|
||||
--print-table-header-text: #000;
|
||||
--print-table-body-bg: #fff;
|
||||
--print-table-body-text: #000;
|
||||
--print-table-border: #ddd;
|
||||
--print-table-hover: #f8f9fa;
|
||||
--print-table-selected: #007bff;
|
||||
--print-card-bg: #fff;
|
||||
--print-card-border: #ddd;
|
||||
--print-search-field-bg: #fff;
|
||||
--print-search-field-text: #000;
|
||||
--print-search-field-border: #ddd;
|
||||
}
|
||||
|
||||
/* Dark mode theme variables */
|
||||
body.dark-mode {
|
||||
--print-table-header-bg: #2a3441;
|
||||
--print-table-header-text: #ffffff;
|
||||
--print-table-body-bg: #2a3441;
|
||||
--print-table-body-text: #ffffff;
|
||||
--print-table-border: #495057;
|
||||
--print-table-hover: #3a4451;
|
||||
--print-table-selected: #007bff;
|
||||
--print-card-bg: #2a2a2a;
|
||||
--print-card-border: #555;
|
||||
--print-search-field-bg: #333;
|
||||
--print-search-field-text: #fff;
|
||||
--print-search-field-border: #555;
|
||||
}
|
||||
|
||||
/* Label Preview Theme Support */
|
||||
body.light-mode #label-preview {
|
||||
background: #fafafa;
|
||||
border: none;
|
||||
}
|
||||
|
||||
body.light-mode #label-content {
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
body.light-mode #barcode-frame,
|
||||
body.light-mode #vertical-barcode-frame {
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--print-card-border);
|
||||
}
|
||||
|
||||
body.dark-mode #label-preview {
|
||||
background: #2a2a2a;
|
||||
border: none;
|
||||
}
|
||||
|
||||
body.dark-mode #label-content {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
|
||||
body.dark-mode #barcode-frame,
|
||||
body.dark-mode #vertical-barcode-frame {
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--print-card-border);
|
||||
}
|
||||
|
||||
/* Card Theme Support */
|
||||
body.dark-mode .search-card,
|
||||
body.dark-mode .card {
|
||||
background-color: var(--print-card-bg);
|
||||
border: 1px solid var(--print-card-border);
|
||||
color: var(--print-table-body-text);
|
||||
}
|
||||
|
||||
/* Search Field Theme Support */
|
||||
body.dark-mode .search-field,
|
||||
body.dark-mode .quantity-field {
|
||||
background-color: var(--print-search-field-bg);
|
||||
border: 1px solid var(--print-search-field-border);
|
||||
color: var(--print-search-field-text);
|
||||
}
|
||||
|
||||
/* Button Theme Support */
|
||||
body.dark-mode .print-btn {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
body.dark-mode .print-btn:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
UTILITY CLASSES
|
||||
========================================================================== */
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.font-weight-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.margin-bottom-15 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.padding-10 {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
DEBUG STYLES (can be removed in production)
|
||||
========================================================================== */
|
||||
|
||||
.debug-border {
|
||||
border: 2px solid red !important;
|
||||
}
|
||||
|
||||
.debug-bg {
|
||||
background-color: rgba(255, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
PRINT MODULE SPECIFIC STYLES
|
||||
========================================================================== */
|
||||
|
||||
/* Label preview container styling for print_module page */
|
||||
.scan-form-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
min-height: 700px;
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* Label preview section */
|
||||
#label-preview {
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
background: #fafafa;
|
||||
width: 100%;
|
||||
max-width: 301px;
|
||||
height: 434.7px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Ensure label content scales properly in responsive layout */
|
||||
@media (max-width: 1024px) {
|
||||
#label-preview {
|
||||
max-width: 280px;
|
||||
height: 404px;
|
||||
}
|
||||
|
||||
.scan-form-card {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#label-preview {
|
||||
max-width: 100%;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.scan-form-card {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
FORM CONTROLS FIX
|
||||
========================================================================== */
|
||||
|
||||
/* Fix radio button styling to prevent oval display issues */
|
||||
.form-check-input[type="radio"] {
|
||||
width: 1rem !important;
|
||||
height: 1rem !important;
|
||||
margin-top: 0.25rem !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
border-radius: 50% !important;
|
||||
background-color: #fff !important;
|
||||
appearance: none !important;
|
||||
-webkit-appearance: none !important;
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
.form-check-input[type="radio"]:checked {
|
||||
background-color: #007bff !important;
|
||||
border-color: #007bff !important;
|
||||
background-image: radial-gradient(circle, #fff 30%, transparent 32%) !important;
|
||||
}
|
||||
|
||||
.form-check-input[type="radio"]:focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25) !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.form-check {
|
||||
display: flex !important;
|
||||
align-items: flex-start !important;
|
||||
margin-bottom: 0.5rem !important;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
margin-left: 0.5rem !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
# Dashboard - Ghid de utilizare
|
||||
|
||||
## Prezentare generală
|
||||
Dashboard-ul este pagina principală a aplicației Quality Management System și oferă o vizualizare de ansamblu asupra tuturor modulelor disponibile și funcționalităților sistemului.
|
||||
|
||||
## Structura Dashboard-ului
|
||||
|
||||
### Bara de navigare superioară
|
||||
În partea de sus a paginii găsiți:
|
||||
- **Logo-ul companiei** - Quality Management
|
||||
- **Meniul principal** cu accesul la toate modulele
|
||||
- **Butonul de profil utilizator** și logout în colțul din dreapta
|
||||
|
||||

|
||||
|
||||
### Sectiuni principale
|
||||

|
||||
#### 1. Modulul Quality (Calitate)
|
||||
Permite gestionarea proceselor de control al calității:
|
||||
- **Scan FG** - Scanarea produselor finite
|
||||
- **Scan RM** - Scanarea materiilor prime
|
||||
- **Reports** - Rapoarte de calitate
|
||||
- **Quality Settings** - Configurări pentru modulul de calitate
|
||||
|
||||

|
||||
|
||||
#### 2. Modulul Warehouse (Depozit)
|
||||
Gestionarea stocurilor și locațiilor din depozit:
|
||||
- **Create Locations** - Crearea de noi locații în depozit
|
||||
- **Store Articles** - Depozitarea articolelor
|
||||
- **Warehouse Reports** - Rapoarte de depozit
|
||||
- **Inventory Management** - Gestionarea inventarului
|
||||
|
||||

|
||||
|
||||
#### 3. Modulul Labels (Etichete)
|
||||
Pentru generarea și printarea etichetelor:
|
||||
- **Print Module** - Printarea etichetelor pentru comenzi
|
||||
- **Print Lost Labels** - Reprintarea etichetelor pierdute
|
||||
- **View Orders** - Vizualizarea comenzilor
|
||||
- **Upload Data** - Încărcarea datelor pentru etichete
|
||||
|
||||

|
||||
|
||||
## Cum să navigați în aplicație
|
||||
|
||||
### Pasul 1: Autentificarea
|
||||
1. Introduceți username-ul și parola
|
||||
2. Faceți clic pe "Login"
|
||||
3. Veți fi redirecționați automat către dashboard
|
||||
|
||||
### Pasul 2: Selectarea modulului
|
||||
1. În dashboard, faceți clic pe modulul dorit (Quality, Warehouse, Labels)
|
||||
2. Veți vedea submeniul cu opțiunile disponibile
|
||||
3. Selectați funcționalitatea dorită
|
||||
|
||||

|
||||
|
||||
### Pasul 3: Utilizarea funcționalităților
|
||||
Fiecare modul are propriile sale funcționalități specializate. Consultați ghidurile specifice pentru:
|
||||
- [Modulul Quality](quality_module.md)
|
||||
- [Modulul Warehouse](warehouse_module.md)
|
||||
- [Modulul Labels](labels_module.md)
|
||||
|
||||
## Permisiuni și acces
|
||||
|
||||
### Tipuri de utilizatori
|
||||
Aplicația suportă diferite niveluri de acces:
|
||||
- **Superadmin** - Acces complet la toate modulele și setări
|
||||
- **Admin** - Acces la majoritatea funcționalităților
|
||||
- **Manager** - Acces la funcționalitățile de management
|
||||
- **User** - Acces limitat la funcționalitățile de bază
|
||||

|
||||
### Verificarea permisiunilor
|
||||
- Dacă nu aveți acces la un modul, acesta nu va fi vizibil în dashboard
|
||||
- Contactați administratorul pentru a obține permisiuni suplimentare
|
||||
- Permisiunile sunt configurate per utilizator și per modul
|
||||
|
||||

|
||||
|
||||
## Funcționalități comune
|
||||
|
||||
### Bara de căutare globală
|
||||
- Folosiți bara de căutare pentru a găsi rapid comenzi, articole sau rapoarte
|
||||
- Căutarea funcționează pe toate modulele activate
|
||||
|
||||
### Notificări sistem
|
||||
- Notificările apar în colțul din dreapta sus
|
||||
- Includ alertele de sistem, confirmări de acțiuni și mesaje de eroare
|
||||
- Faceți clic pe notificare pentru a o închide
|
||||
|
||||
### Shortcuts tastatura
|
||||
- **Ctrl + H** - Întoarcere la dashboard
|
||||
- **Ctrl + L** - Focus pe bara de căutare
|
||||
- **Escape** - Închiderea modalelor deschise
|
||||
|
||||
## Rezolvarea problemelor comune
|
||||
|
||||
### Nu se încarcă dashboard-ul
|
||||
1. Verificați conexiunea la internet
|
||||
2. Reîncărcați pagina (F5)
|
||||
3. Ștergeți cache-ul browserului
|
||||
4. Contactați administratorul IT
|
||||
|
||||
### Lipsesc module din dashboard
|
||||
1. Verificați că sunteți autentificat corect
|
||||
2. Contactați administratorul pentru verificarea permisiunilor
|
||||
3. Unele module pot fi temporar dezactivate pentru mentenanță
|
||||
|
||||
### Performanțe lente
|
||||
1. Închideți tab-urile de browser nefolosite
|
||||
2. Verificați conexiunea la rețea
|
||||
3. Raportați problema administratorului IT
|
||||
|
||||
## Contacte și suport
|
||||
|
||||
### Suport tehnic
|
||||
- **Email**: it-support@recticel.com
|
||||
- **Telefon intern**: 1234
|
||||
- **Program**: L-V, 08:00-17:00
|
||||
|
||||
### Documentație suplimentară
|
||||
- [Manual complet utilizator](user_manual.pdf)
|
||||
- [Ghid rapid](quick_start.md)
|
||||
- [FAQ - Întrebări frecvente](faq.md)
|
||||
|
||||
### Actualizări sistem
|
||||
Sistemul este actualizat regulat. Consultați [pagina de changelog](changelog.md) pentru ultimele noutăți și îmbunătățiri.
|
||||
|
||||
---
|
||||
*Ultima actualizare: Octombrie 2025*
|
||||
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,48 +0,0 @@
|
||||
# Print Module - Ghid de utilizare
|
||||
|
||||
## Prezentare generală
|
||||
Modulul de printare permite generarea și printarea etichetelor pentru comenzile de producție.
|
||||
|
||||
## Pași pentru printarea etichetelor
|
||||
|
||||
### Pasul 1: Selectarea comenzii
|
||||
1. Accesați pagina **Print Module** din meniul principal
|
||||
2. În tabelul din dreapta, căutați comanda dorită
|
||||
3. Faceți clic pe linia corespunzătoare pentru a o selecta
|
||||
|
||||

|
||||
|
||||
### Pasul 2: Verificarea previzualizării
|
||||
1. În panoul din stânga veți vedea previzualizarea etichetei
|
||||
2. Verificați că toate informațiile sunt corecte:
|
||||
- Numele clientului
|
||||
- Cantitatea comandată
|
||||
- Data livrării
|
||||
- Descrierea produsului
|
||||
|
||||

|
||||
|
||||
### Pasul 3: Configurarea printării
|
||||
1. Selectați metoda de printare:
|
||||
- **🖨️ Direct Print**: Printare directă prin QZ Tray
|
||||
- **📄 PDF Export**: Generare fișier PDF
|
||||
2. Pentru printarea directă, selectați imprimanta dorită din listă
|
||||
|
||||
### Pasul 4: Printarea
|
||||
1. Faceți clic pe butonul **🖨️ Print Labels**
|
||||
2. Verificați că eticheta a fost printată corect
|
||||
|
||||
## Rezolvarea problemelor
|
||||
|
||||
### QZ Tray nu este conectat
|
||||
- Descărcați și instalați QZ Tray din linkul furnizat
|
||||
- Asigurați-vă că aplicația QZ Tray rulează
|
||||
- Verificați că imprimanta este conectată și configurată
|
||||
|
||||
### Codul de bare nu se afișează
|
||||
- Verificați conexiunea la internet
|
||||
- Reîncărcați pagina
|
||||
- Contactați administratorul dacă problema persistă
|
||||
|
||||
## Contacte
|
||||
Pentru probleme tehnice, contactați echipa IT.
|
||||
@@ -1,539 +0,0 @@
|
||||
// FG Quality specific JavaScript - Standalone version
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Prevent conflicts with main script.js by removing existing listeners
|
||||
console.log('FG Quality JavaScript loaded');
|
||||
|
||||
const reportButtons = document.querySelectorAll('.report-btn');
|
||||
const reportTable = document.getElementById('report-table');
|
||||
const reportTitle = document.getElementById('report-title');
|
||||
const exportCsvButton = document.getElementById('export-csv');
|
||||
|
||||
// Calendar elements
|
||||
const calendarModal = document.getElementById('calendar-modal');
|
||||
const dateRangeModal = document.getElementById('date-range-modal');
|
||||
const selectDayReport = document.getElementById('select-day-report');
|
||||
const selectDayDefectsReport = document.getElementById('select-day-defects-report');
|
||||
const dateRangeReport = document.getElementById('date-range-report');
|
||||
const dateRangeDefectsReport = document.getElementById('date-range-defects-report');
|
||||
|
||||
let currentReportType = null;
|
||||
let currentDate = new Date();
|
||||
let selectedDate = null;
|
||||
|
||||
// Clear any existing event listeners by cloning elements
|
||||
function clearExistingListeners() {
|
||||
if (selectDayReport) {
|
||||
const newSelectDayReport = selectDayReport.cloneNode(true);
|
||||
selectDayReport.parentNode.replaceChild(newSelectDayReport, selectDayReport);
|
||||
}
|
||||
if (selectDayDefectsReport) {
|
||||
const newSelectDayDefectsReport = selectDayDefectsReport.cloneNode(true);
|
||||
selectDayDefectsReport.parentNode.replaceChild(newSelectDayDefectsReport, selectDayDefectsReport);
|
||||
}
|
||||
if (dateRangeReport) {
|
||||
const newDateRangeReport = dateRangeReport.cloneNode(true);
|
||||
dateRangeReport.parentNode.replaceChild(newDateRangeReport, dateRangeReport);
|
||||
}
|
||||
if (dateRangeDefectsReport) {
|
||||
const newDateRangeDefectsReport = dateRangeDefectsReport.cloneNode(true);
|
||||
dateRangeDefectsReport.parentNode.replaceChild(newDateRangeDefectsReport, dateRangeDefectsReport);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear existing listeners first
|
||||
clearExistingListeners();
|
||||
|
||||
// Re-get elements after cloning
|
||||
const newSelectDayReport = document.getElementById('select-day-report');
|
||||
const newSelectDayDefectsReport = document.getElementById('select-day-defects-report');
|
||||
const newDateRangeReport = document.getElementById('date-range-report');
|
||||
const newDateRangeDefectsReport = document.getElementById('date-range-defects-report');
|
||||
|
||||
// Add event listeners to report buttons
|
||||
reportButtons.forEach(button => {
|
||||
const reportType = button.getAttribute('data-report');
|
||||
if (reportType) {
|
||||
// Clone to remove existing listeners
|
||||
const newButton = button.cloneNode(true);
|
||||
button.parentNode.replaceChild(newButton, button);
|
||||
|
||||
newButton.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('FG Report button clicked:', reportType);
|
||||
fetchFGReportData(reportType);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Calendar-based report buttons with FG-specific handlers
|
||||
if (newSelectDayReport) {
|
||||
newSelectDayReport.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('FG Select Day Report clicked');
|
||||
currentReportType = '6';
|
||||
showCalendarModal();
|
||||
});
|
||||
}
|
||||
|
||||
if (newSelectDayDefectsReport) {
|
||||
newSelectDayDefectsReport.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('FG Select Day Defects Report clicked');
|
||||
currentReportType = '8';
|
||||
showCalendarModal();
|
||||
});
|
||||
}
|
||||
|
||||
if (newDateRangeReport) {
|
||||
newDateRangeReport.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('FG Date Range Report clicked');
|
||||
currentReportType = '7';
|
||||
showDateRangeModal();
|
||||
});
|
||||
}
|
||||
|
||||
if (newDateRangeDefectsReport) {
|
||||
newDateRangeDefectsReport.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('FG Date Range Defects Report clicked');
|
||||
currentReportType = '9';
|
||||
showDateRangeModal();
|
||||
});
|
||||
}
|
||||
|
||||
// Function to fetch FG report data
|
||||
function fetchFGReportData(reportType) {
|
||||
const url = `/get_fg_report_data?report=${reportType}`;
|
||||
console.log('Fetching FG data from:', url);
|
||||
reportTitle.textContent = 'Loading FG data...';
|
||||
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('FG Report data received:', data);
|
||||
if (data.error) {
|
||||
reportTitle.textContent = data.error;
|
||||
return;
|
||||
}
|
||||
|
||||
populateFGTable(data);
|
||||
updateReportTitle(reportType);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching FG report data:', error);
|
||||
reportTitle.textContent = 'Error loading FG data.';
|
||||
});
|
||||
}
|
||||
|
||||
// Function to fetch FG report data for specific dates
|
||||
function fetchFGDateReportData(reportType, date, startDate = null, endDate = null) {
|
||||
let url = `/generate_fg_report?report=${reportType}`;
|
||||
if (date) {
|
||||
url += `&date=${date}`;
|
||||
}
|
||||
if (startDate && endDate) {
|
||||
url += `&start_date=${startDate}&end_date=${endDate}`;
|
||||
}
|
||||
|
||||
console.log('Fetching FG date report from:', url);
|
||||
reportTitle.textContent = 'Loading FG data...';
|
||||
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('FG Date report data received:', data);
|
||||
if (data.error) {
|
||||
reportTitle.textContent = data.error;
|
||||
return;
|
||||
}
|
||||
|
||||
populateFGTable(data);
|
||||
updateDateReportTitle(reportType, date, startDate, endDate);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching FG date report data:', error);
|
||||
reportTitle.textContent = 'Error loading FG data.';
|
||||
});
|
||||
}
|
||||
|
||||
// Function to populate the table with FG data
|
||||
function populateFGTable(data) {
|
||||
const thead = reportTable.querySelector('thead tr');
|
||||
const tbody = reportTable.querySelector('tbody');
|
||||
|
||||
// Clear existing content
|
||||
thead.innerHTML = '';
|
||||
tbody.innerHTML = '';
|
||||
|
||||
// Add headers
|
||||
if (data.headers && data.headers.length > 0) {
|
||||
data.headers.forEach(header => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = header;
|
||||
thead.appendChild(th);
|
||||
});
|
||||
}
|
||||
|
||||
// Add rows
|
||||
if (data.rows && data.rows.length > 0) {
|
||||
data.rows.forEach(row => {
|
||||
const tr = document.createElement('tr');
|
||||
row.forEach(cell => {
|
||||
const td = document.createElement('td');
|
||||
td.textContent = cell || '';
|
||||
tr.appendChild(td);
|
||||
});
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
} else {
|
||||
// Show no data message
|
||||
const tr = document.createElement('tr');
|
||||
const td = document.createElement('td');
|
||||
td.colSpan = data.headers ? data.headers.length : 1;
|
||||
td.textContent = data.message || 'No FG data found for the selected criteria.';
|
||||
td.style.textAlign = 'center';
|
||||
td.style.fontStyle = 'italic';
|
||||
td.style.padding = '20px';
|
||||
tr.appendChild(td);
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update report title based on type
|
||||
function updateReportTitle(reportType) {
|
||||
const titles = {
|
||||
'1': 'Daily Complete FG Orders Report',
|
||||
'2': '5-Day Complete FG Orders Report',
|
||||
'3': 'FG Items with Defects for Current Day',
|
||||
'4': 'FG Items with Defects for Last 5 Days',
|
||||
'5': 'Complete FG Database Report'
|
||||
};
|
||||
|
||||
reportTitle.textContent = titles[reportType] || 'FG Quality Report';
|
||||
}
|
||||
|
||||
// Function to update report title for date-based reports
|
||||
function updateDateReportTitle(reportType, date, startDate, endDate) {
|
||||
const titles = {
|
||||
'6': `FG Daily Report for ${date}`,
|
||||
'7': `FG Date Range Report (${startDate} to ${endDate})`,
|
||||
'8': `FG Quality Defects Report for ${date}`,
|
||||
'9': `FG Quality Defects Range Report (${startDate} to ${endDate})`
|
||||
};
|
||||
|
||||
reportTitle.textContent = titles[reportType] || 'FG Quality Report';
|
||||
}
|
||||
|
||||
// Calendar functionality
|
||||
function showCalendarModal() {
|
||||
if (calendarModal) {
|
||||
calendarModal.style.display = 'block';
|
||||
generateCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
function hideCalendarModal() {
|
||||
if (calendarModal) {
|
||||
calendarModal.style.display = 'none';
|
||||
selectedDate = null;
|
||||
updateConfirmButton();
|
||||
}
|
||||
}
|
||||
|
||||
function showDateRangeModal() {
|
||||
if (dateRangeModal) {
|
||||
dateRangeModal.style.display = 'block';
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
document.getElementById('start-date').value = today;
|
||||
document.getElementById('end-date').value = today;
|
||||
}
|
||||
}
|
||||
|
||||
function hideDataRangeModal() {
|
||||
if (dateRangeModal) {
|
||||
dateRangeModal.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function generateCalendar() {
|
||||
const calendarDays = document.getElementById('calendar-days');
|
||||
const monthYear = document.getElementById('calendar-month-year');
|
||||
|
||||
if (!calendarDays || !monthYear) return;
|
||||
|
||||
const year = currentDate.getFullYear();
|
||||
const month = currentDate.getMonth();
|
||||
|
||||
monthYear.textContent = `${currentDate.toLocaleString('default', { month: 'long' })} ${year}`;
|
||||
|
||||
// Clear previous days
|
||||
calendarDays.innerHTML = '';
|
||||
|
||||
// Get first day of month and number of days
|
||||
const firstDay = new Date(year, month, 1).getDay();
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
|
||||
// Add empty cells for previous month
|
||||
for (let i = 0; i < firstDay; i++) {
|
||||
const emptyDay = document.createElement('div');
|
||||
emptyDay.className = 'calendar-day empty';
|
||||
calendarDays.appendChild(emptyDay);
|
||||
}
|
||||
|
||||
// Add days of current month
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const dayElement = document.createElement('div');
|
||||
dayElement.className = 'calendar-day';
|
||||
dayElement.textContent = day;
|
||||
|
||||
// Check if it's today
|
||||
const today = new Date();
|
||||
if (year === today.getFullYear() && month === today.getMonth() && day === today.getDate()) {
|
||||
dayElement.classList.add('today');
|
||||
}
|
||||
|
||||
dayElement.addEventListener('click', () => {
|
||||
// Remove previous selection
|
||||
document.querySelectorAll('.calendar-day.selected').forEach(el => {
|
||||
el.classList.remove('selected');
|
||||
});
|
||||
|
||||
// Add selection to clicked day
|
||||
dayElement.classList.add('selected');
|
||||
|
||||
// Set selected date
|
||||
selectedDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||
console.log('FG Calendar date selected:', selectedDate);
|
||||
updateConfirmButton();
|
||||
});
|
||||
|
||||
calendarDays.appendChild(dayElement);
|
||||
}
|
||||
}
|
||||
|
||||
function updateConfirmButton() {
|
||||
const confirmButton = document.getElementById('confirm-date');
|
||||
if (confirmButton) {
|
||||
confirmButton.disabled = !selectedDate;
|
||||
}
|
||||
}
|
||||
|
||||
// Calendar navigation
|
||||
const prevMonthBtn = document.getElementById('prev-month');
|
||||
const nextMonthBtn = document.getElementById('next-month');
|
||||
|
||||
if (prevMonthBtn) {
|
||||
// Clone to remove existing listeners
|
||||
const newPrevBtn = prevMonthBtn.cloneNode(true);
|
||||
prevMonthBtn.parentNode.replaceChild(newPrevBtn, prevMonthBtn);
|
||||
|
||||
newPrevBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
currentDate.setMonth(currentDate.getMonth() - 1);
|
||||
generateCalendar();
|
||||
});
|
||||
}
|
||||
|
||||
if (nextMonthBtn) {
|
||||
// Clone to remove existing listeners
|
||||
const newNextBtn = nextMonthBtn.cloneNode(true);
|
||||
nextMonthBtn.parentNode.replaceChild(newNextBtn, nextMonthBtn);
|
||||
|
||||
newNextBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
currentDate.setMonth(currentDate.getMonth() + 1);
|
||||
generateCalendar();
|
||||
});
|
||||
}
|
||||
|
||||
// Calendar modal buttons
|
||||
const cancelDateBtn = document.getElementById('cancel-date');
|
||||
const confirmDateBtn = document.getElementById('confirm-date');
|
||||
|
||||
if (cancelDateBtn) {
|
||||
// Clone to remove existing listeners
|
||||
const newCancelBtn = cancelDateBtn.cloneNode(true);
|
||||
cancelDateBtn.parentNode.replaceChild(newCancelBtn, cancelDateBtn);
|
||||
|
||||
newCancelBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
hideCalendarModal();
|
||||
});
|
||||
}
|
||||
|
||||
if (confirmDateBtn) {
|
||||
// Clone to remove existing listeners
|
||||
const newConfirmBtn = confirmDateBtn.cloneNode(true);
|
||||
confirmDateBtn.parentNode.replaceChild(newConfirmBtn, confirmDateBtn);
|
||||
|
||||
newConfirmBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('FG Calendar confirm clicked with date:', selectedDate, 'report type:', currentReportType);
|
||||
if (selectedDate && currentReportType) {
|
||||
fetchFGDateReportData(currentReportType, selectedDate);
|
||||
hideCalendarModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Date range modal buttons
|
||||
const cancelDateRangeBtn = document.getElementById('cancel-date-range');
|
||||
const confirmDateRangeBtn = document.getElementById('confirm-date-range');
|
||||
|
||||
if (cancelDateRangeBtn) {
|
||||
// Clone to remove existing listeners
|
||||
const newCancelRangeBtn = cancelDateRangeBtn.cloneNode(true);
|
||||
cancelDateRangeBtn.parentNode.replaceChild(newCancelRangeBtn, cancelDateRangeBtn);
|
||||
|
||||
newCancelRangeBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
hideDataRangeModal();
|
||||
});
|
||||
}
|
||||
|
||||
if (confirmDateRangeBtn) {
|
||||
// Clone to remove existing listeners
|
||||
const newConfirmRangeBtn = confirmDateRangeBtn.cloneNode(true);
|
||||
confirmDateRangeBtn.parentNode.replaceChild(newConfirmRangeBtn, confirmDateRangeBtn);
|
||||
|
||||
newConfirmRangeBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const startDate = document.getElementById('start-date').value;
|
||||
const endDate = document.getElementById('end-date').value;
|
||||
|
||||
console.log('FG Date range confirm clicked:', startDate, 'to', endDate, 'report type:', currentReportType);
|
||||
if (startDate && endDate && currentReportType) {
|
||||
fetchFGDateReportData(currentReportType, null, startDate, endDate);
|
||||
hideDataRangeModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Enable/disable date range confirm button
|
||||
const startDateInput = document.getElementById('start-date');
|
||||
const endDateInput = document.getElementById('end-date');
|
||||
|
||||
function updateDateRangeConfirmButton() {
|
||||
const confirmBtn = document.getElementById('confirm-date-range');
|
||||
if (confirmBtn && startDateInput && endDateInput) {
|
||||
confirmBtn.disabled = !startDateInput.value || !endDateInput.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (startDateInput) {
|
||||
startDateInput.addEventListener('change', updateDateRangeConfirmButton);
|
||||
}
|
||||
|
||||
if (endDateInput) {
|
||||
endDateInput.addEventListener('change', updateDateRangeConfirmButton);
|
||||
}
|
||||
|
||||
// Close modals when clicking outside
|
||||
window.addEventListener('click', (event) => {
|
||||
if (event.target === calendarModal) {
|
||||
hideCalendarModal();
|
||||
}
|
||||
if (event.target === dateRangeModal) {
|
||||
hideDataRangeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Close modals with X button
|
||||
document.querySelectorAll('.close-modal').forEach(closeBtn => {
|
||||
// Clone to remove existing listeners
|
||||
const newCloseBtn = closeBtn.cloneNode(true);
|
||||
closeBtn.parentNode.replaceChild(newCloseBtn, closeBtn);
|
||||
|
||||
newCloseBtn.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const modal = event.target.closest('.modal');
|
||||
if (modal) {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Export functionality
|
||||
if (exportCsvButton) {
|
||||
exportCsvButton.addEventListener('click', () => {
|
||||
const rows = reportTable.querySelectorAll('tr');
|
||||
if (rows.length === 0) {
|
||||
alert('No FG data available to export.');
|
||||
return;
|
||||
}
|
||||
const reportTitleText = reportTitle.textContent.trim();
|
||||
const filename = `${reportTitleText.replace(/\s+/g, '_')}.csv`;
|
||||
exportTableToCSV(filename);
|
||||
});
|
||||
}
|
||||
|
||||
// Export to CSV function
|
||||
function exportTableToCSV(filename) {
|
||||
const table = reportTable;
|
||||
const rows = Array.from(table.querySelectorAll('tr'));
|
||||
|
||||
const csvContent = rows.map(row => {
|
||||
const cells = Array.from(row.querySelectorAll('th, td'));
|
||||
return cells.map(cell => {
|
||||
let text = cell.textContent.trim();
|
||||
// Escape quotes and wrap in quotes if necessary
|
||||
if (text.includes(',') || text.includes('"') || text.includes('\n')) {
|
||||
text = '"' + text.replace(/"/g, '""') + '"';
|
||||
}
|
||||
return text;
|
||||
}).join(',');
|
||||
}).join('\n');
|
||||
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
const url = URL.createObjectURL(blob);
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', filename);
|
||||
link.style.visibility = 'hidden';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
// Test Database Button
|
||||
const testDatabaseBtn = document.getElementById('test-database');
|
||||
if (testDatabaseBtn) {
|
||||
testDatabaseBtn.addEventListener('click', () => {
|
||||
console.log('Testing FG database connection...');
|
||||
reportTitle.textContent = 'Testing FG Database Connection...';
|
||||
fetch('/test_fg_database')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('FG Database test results:', data);
|
||||
if (data.success) {
|
||||
reportTitle.textContent = `FG Database Test Results - ${data.total_records} records found`;
|
||||
// Show alert with summary
|
||||
alert(`FG Database Test Complete!\n\nConnection: ${data.database_connection}\nTable exists: ${data.table_exists}\nTotal records: ${data.total_records}\nMessage: ${data.message}`);
|
||||
} else {
|
||||
reportTitle.textContent = 'FG Database Test Failed';
|
||||
alert(`FG Database test failed: ${data.message}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('FG Database test error:', error);
|
||||
reportTitle.textContent = 'Error testing FG database.';
|
||||
alert('Error testing FG database connection.');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
console.log('FG Quality JavaScript setup complete');
|
||||
});
|
||||
@@ -806,20 +806,6 @@ body.dark-mode .export-description {
|
||||
background-color: #218838; /* Darker green on hover */
|
||||
}
|
||||
|
||||
.go-to-main-reports-btn {
|
||||
background-color: #007bff; /* Blue background */
|
||||
color: #fff; /* White text */
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
margin-left: 10px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.go-to-main-reports-btn:hover {
|
||||
background-color: #0056b3; /* Darker blue on hover */
|
||||
}
|
||||
|
||||
.draggable-field {
|
||||
cursor: move;
|
||||
padding: 5px;
|
||||
|
||||
@@ -4,20 +4,11 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Flask App{% endblock %}</title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<!-- Base CSS for common styles -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
|
||||
<!-- Legacy CSS for backward compatibility (temporarily) -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<!-- Print Module CSS for Labels/Printing pages -->
|
||||
{% if request.endpoint in ['main.etichete', 'main.upload_data', 'main.view_orders', 'main.print_module', 'main.print_lost_labels'] %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/print_module.css') }}">
|
||||
{% endif %}
|
||||
<!-- Page-specific CSS -->
|
||||
{% block extra_css %}{% endblock %}
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body class="light-mode">
|
||||
@@ -30,12 +21,8 @@
|
||||
<span class="page-title">Welcome to Dashboard</span>
|
||||
{% elif request.endpoint == 'main.settings' %}
|
||||
<span class="page-title">Settings</span>
|
||||
{% elif request.endpoint == 'main.reports' %}
|
||||
<span class="page-title">Reports Module</span>
|
||||
{% elif request.endpoint == 'main.quality' %}
|
||||
<span class="page-title">Quality Module</span>
|
||||
{% elif request.endpoint == 'main.fg_quality' %}
|
||||
<span class="page-title">FG Quality Module</span>
|
||||
{% elif request.endpoint == 'main.warehouse' %}
|
||||
<span class="page-title">Warehouse Module</span>
|
||||
{% elif request.endpoint == 'main.scan' %}
|
||||
@@ -43,18 +30,15 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="right-header">
|
||||
<button id="theme-toggle" class="theme-toggle">Change to dark theme</button>
|
||||
{% if request.endpoint.startswith('daily_mirror') %}
|
||||
<a href="{{ url_for('daily_mirror.daily_mirror_main_route') }}" class="btn btn-info btn-sm ms-2"> <i class="fas fa-home"></i> Daily Mirror Main</a>
|
||||
{% endif %}
|
||||
{% if request.endpoint in ['main.etichete', 'main.upload_data', 'main.view_orders', 'main.print_module', 'main.print_lost_labels'] %}
|
||||
<a href="{{ url_for('main.etichete') }}" class="btn btn-success btn-sm ms-2"> <i class="fas fa-tags"></i> Labels Module</a>
|
||||
{% endif %}
|
||||
<a href="{{ url_for('main.dashboard') }}" class="btn go-to-dashboard-btn ms-2">Go to Dashboard</a>
|
||||
{% if 'user' in session %}
|
||||
<span class="user-info ms-2">You are logged in as {{ session['user'] }}</span>
|
||||
<a href="{{ url_for('main.logout') }}" class="logout-button ms-2">Logout</a>
|
||||
{% endif %}
|
||||
<button id="theme-toggle" class="theme-toggle">Change to dark theme</button>
|
||||
{% if request.endpoint in ['main.upload_data', 'main.upload_orders', 'main.print_module', 'main.label_templates', 'main.create_template', 'main.print_lost_labels', 'main.view_orders'] %}
|
||||
<a href="{{ url_for('main.etichete') }}" class="btn go-to-main-etichete-btn">Main Page Etichete</a>
|
||||
{% endif %}
|
||||
<a href="{{ url_for('main.dashboard') }}" class="btn go-to-dashboard-btn">Go to Dashboard</a>
|
||||
{% if 'user' in session %}
|
||||
<span class="user-info">You are logged in as {{ session['user'] }}</span>
|
||||
<a href="{{ url_for('main.logout') }}" class="logout-button">Logout</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -62,11 +46,6 @@
|
||||
<div class="main-content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% if request.endpoint != 'main.fg_quality' %}
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
{% endif %}
|
||||
|
||||
<!-- Bootstrap JavaScript -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,6 @@
|
||||
{% block title %}Create Warehouse Locations{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/warehouse.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
@@ -401,72 +400,20 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// Edit button functionality
|
||||
editButton.addEventListener('click', function() {
|
||||
console.log('Edit button clicked', selectedLocation);
|
||||
if (selectedLocation) {
|
||||
openEditModal(selectedLocation);
|
||||
} else {
|
||||
showNotification('❌ No location selected', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Delete button functionality
|
||||
deleteButton.addEventListener('click', function() {
|
||||
console.log('Delete button clicked', selectedLocation);
|
||||
if (selectedLocation) {
|
||||
openDeleteModal(selectedLocation);
|
||||
} else {
|
||||
showNotification('❌ No location selected', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize QZ Tray
|
||||
initializeQZTray();
|
||||
|
||||
// Handle edit form submission
|
||||
document.getElementById('edit-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
const data = {
|
||||
location_id: parseInt(formData.get('location_id')),
|
||||
location_code: formData.get('location_code'),
|
||||
size: formData.get('size') ? parseInt(formData.get('size')) : null,
|
||||
description: formData.get('description') || null
|
||||
};
|
||||
|
||||
console.log('Attempting to update location:', data);
|
||||
|
||||
// Send update request
|
||||
fetch("{{ url_for('warehouse.update_location') }}", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Update response status:', response.status);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(result => {
|
||||
console.log('Update result:', result);
|
||||
if (result.success) {
|
||||
showNotification('✅ Location updated successfully!', 'success');
|
||||
closeEditModal();
|
||||
// Reload page to show changes
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
showNotification('❌ Error updating location: ' + result.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('❌ Error updating location: ' + error.message, 'error');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Print barcode function with enhanced QZ Tray support
|
||||
@@ -490,7 +437,7 @@ async function printLocationBarcode() {
|
||||
printStatus.textContent = 'Generating label...';
|
||||
|
||||
// Generate PDF for the 4x8cm label
|
||||
const response = await fetch("{{ url_for('warehouse.generate_location_label_pdf') }}", {
|
||||
const response = await fetch('/generate_location_label_pdf', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -622,31 +569,22 @@ document.getElementById('edit-form').addEventListener('submit', function(e) {
|
||||
|
||||
const formData = new FormData(this);
|
||||
const data = {
|
||||
location_id: parseInt(formData.get('location_id')),
|
||||
location_id: formData.get('location_id'),
|
||||
location_code: formData.get('location_code'),
|
||||
size: formData.get('size') ? parseInt(formData.get('size')) : null,
|
||||
description: formData.get('description') || null
|
||||
size: formData.get('size'),
|
||||
description: formData.get('description')
|
||||
};
|
||||
|
||||
console.log('Attempting to update location:', data);
|
||||
|
||||
// Send update request
|
||||
fetch("{{ url_for('warehouse.update_location') }}", {
|
||||
fetch('/update_location', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Update response status:', response.status);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
console.log('Update result:', result);
|
||||
if (result.success) {
|
||||
showNotification('✅ Location updated successfully!', 'success');
|
||||
closeEditModal();
|
||||
@@ -662,46 +600,6 @@ document.getElementById('edit-form').addEventListener('submit', function(e) {
|
||||
});
|
||||
});
|
||||
|
||||
// Handle delete confirmation
|
||||
function confirmDelete() {
|
||||
const locationId = document.getElementById('delete-confirm-id').textContent;
|
||||
|
||||
console.log('Attempting to delete location ID:', locationId);
|
||||
|
||||
// Send delete request
|
||||
fetch("{{ url_for('warehouse.delete_location') }}", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
location_id: parseInt(locationId)
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Delete response status:', response.status);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(result => {
|
||||
console.log('Delete result:', result);
|
||||
if (result.success) {
|
||||
showNotification('✅ Location deleted successfully!', 'success');
|
||||
closeDeleteModal();
|
||||
// Reload page to show changes
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
showNotification('❌ Error deleting location: ' + result.error, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('❌ Error deleting location: ' + error.message, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Handle delete confirmation
|
||||
function confirmDelete() {
|
||||
const locationId = document.getElementById('delete-confirm-id').textContent;
|
||||
@@ -746,271 +644,4 @@ window.addEventListener('click', function(event) {
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit Location Modal -->
|
||||
<div id="edit-modal" class="modal" style="display: none;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Edit Location</h3>
|
||||
<span class="close" onclick="closeEditModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="edit-form">
|
||||
<input type="hidden" id="edit-location-id" name="location_id">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-location-code">Location Code:</label>
|
||||
<input type="text" id="edit-location-code" name="location_code" maxlength="12" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-size">Size:</label>
|
||||
<input type="number" id="edit-size" name="size">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-description">Description:</label>
|
||||
<input type="text" id="edit-description" name="description" maxlength="250">
|
||||
</div>
|
||||
|
||||
<div class="modal-buttons">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeEditModal()">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Update Location</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Location Modal -->
|
||||
<div id="delete-modal" class="modal" style="display: none;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Delete Location</h3>
|
||||
<span class="close" onclick="closeDeleteModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to delete this location?</p>
|
||||
<div class="delete-info">
|
||||
<strong>ID:</strong> <span id="delete-confirm-id"></span><br>
|
||||
<strong>Code:</strong> <span id="delete-confirm-code"></span><br>
|
||||
<strong>Size:</strong> <span id="delete-confirm-size"></span><br>
|
||||
<strong>Description:</strong> <span id="delete-confirm-description"></span>
|
||||
</div>
|
||||
<p style="color: #d32f2f; font-weight: bold;">This action cannot be undone!</p>
|
||||
</div>
|
||||
<div class="modal-buttons">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeDeleteModal()">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" onclick="confirmDelete()">Delete Location</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Modal Styles */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--app-overlay-bg, rgba(0, 0, 0, 0.5));
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: var(--app-card-bg, #f8fafc);
|
||||
color: var(--app-card-text, #1e293b);
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
animation: modalFadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes modalFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20px 25px;
|
||||
border-bottom: 1px solid #cbd5e1;
|
||||
background-color: var(--app-card-bg, #f8fafc);
|
||||
}
|
||||
|
||||
.modal-header h3 {
|
||||
margin: 0;
|
||||
font-size: 1.3em;
|
||||
font-weight: 600;
|
||||
color: var(--app-card-text, #1e293b);
|
||||
}
|
||||
|
||||
.close {
|
||||
color: var(--app-card-text, #1e293b);
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: #e11d48;
|
||||
background-color: #f1f5f9;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 25px;
|
||||
background-color: var(--app-card-bg, #f8fafc);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: var(--app-label-text, #334155);
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.form-group input {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 6px;
|
||||
background-color: var(--app-input-bg, #e2e8f0);
|
||||
color: var(--app-input-text, #1e293b);
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.form-group input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.modal-buttons {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: flex-end;
|
||||
padding: 20px 25px;
|
||||
border-top: 1px solid #cbd5e1;
|
||||
background-color: var(--app-card-bg, #f8fafc);
|
||||
}
|
||||
|
||||
.modal-buttons .btn {
|
||||
padding: 10px 20px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
min-width: 100px;
|
||||
transition: all 0.2s ease;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-buttons .btn-primary {
|
||||
background: #1e293b;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.modal-buttons .btn-primary:hover {
|
||||
background: #0f172a;
|
||||
}
|
||||
|
||||
.modal-buttons .btn-secondary {
|
||||
background: #e11d48;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.modal-buttons .btn-secondary:hover {
|
||||
background: #be185d;
|
||||
}
|
||||
|
||||
.delete-info {
|
||||
background-color: #fef3c7;
|
||||
border: 1px solid #f59e0b;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
margin: 15px 0;
|
||||
border-left: 4px solid #f59e0b;
|
||||
color: var(--app-card-text, #1e293b);
|
||||
}
|
||||
|
||||
.delete-info strong {
|
||||
color: var(--text-color, #333);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color, #007bff);
|
||||
color: white;
|
||||
border: 2px solid var(--primary-color, #007bff);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--primary-hover-color, #0056b3);
|
||||
border-color: var(--primary-hover-color, #0056b3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--secondary-color, #6c757d);
|
||||
color: white;
|
||||
border: 2px solid var(--secondary-color, #6c757d);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: var(--secondary-hover-color, #545b62);
|
||||
border-color: var(--secondary-hover-color, #545b62);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: var(--danger-color, #dc3545);
|
||||
color: white;
|
||||
border: 2px solid var(--danger-color, #dc3545);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background-color: var(--danger-hover-color, #c82333);
|
||||
border-color: var(--danger-hover-color, #c82333);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,447 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Daily Mirror - Quality Recticel{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Page Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">📈 Daily Mirror</h1>
|
||||
<p class="text-muted">Generate comprehensive daily production reports</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ url_for('daily_mirror.daily_mirror_history_route') }}" class="btn btn-outline-primary">
|
||||
<i class="fas fa-history"></i> View History
|
||||
</a>
|
||||
<a href="{{ url_for('main.dashboard') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date Selection Card -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-calendar-alt"></i> Select Report Date
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<label for="reportDate" class="form-label">Report Date:</label>
|
||||
<input type="date" class="form-control" id="reportDate" value="{{ today }}">
|
||||
</div>
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-primary" onclick="generateDailyReport()">
|
||||
<i class="fas fa-chart-line"></i> Generate Report
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-success" onclick="setTodayDate()">
|
||||
<i class="fas fa-calendar-day"></i> Today's Report
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<div id="loadingIndicator" class="row mb-4" style="display: none;">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2 mb-0">Generating daily report...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Daily Report Results -->
|
||||
<div id="reportResults" style="display: none;">
|
||||
<!-- Key Metrics Overview -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-tachometer-alt"></i> Daily Production Overview
|
||||
<span id="reportDateDisplay" class="badge bg-primary ms-2"></span>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="metric-card orders-quantity">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-clipboard-list"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<h3 id="ordersQuantity">-</h3>
|
||||
<p>Orders Quantity</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="metric-card production-launched">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-play-circle"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<h3 id="productionLaunched">-</h3>
|
||||
<p>Production Launched</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="metric-card production-finished">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<h3 id="productionFinished">-</h3>
|
||||
<p>Production Finished</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="metric-card orders-delivered">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-truck"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<h3 id="ordersDelivered">-</h3>
|
||||
<p>Orders Delivered</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quality Control Metrics -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-search"></i> Quality Control Scans
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="quality-stats">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="stat-item">
|
||||
<h4 id="qualityTotalScans">-</h4>
|
||||
<p>Total Scans</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="stat-item approved">
|
||||
<h4 id="qualityApprovedScans">-</h4>
|
||||
<p>Approved</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="stat-item rejected">
|
||||
<h4 id="qualityRejectedScans">-</h4>
|
||||
<p>Rejected</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div class="progress">
|
||||
<div id="qualityApprovalBar" class="progress-bar bg-success" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
<p class="text-center mt-2 mb-0">
|
||||
Approval Rate: <span id="qualityApprovalRate" class="fw-bold">0%</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-clipboard-check"></i> Finish Goods Quality
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="quality-stats">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="stat-item">
|
||||
<h4 id="fgQualityTotalScans">-</h4>
|
||||
<p>Total Scans</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="stat-item approved">
|
||||
<h4 id="fgQualityApprovedScans">-</h4>
|
||||
<p>Approved</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="stat-item rejected">
|
||||
<h4 id="fgQualityRejectedScans">-</h4>
|
||||
<p>Rejected</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div class="progress">
|
||||
<div id="fgQualityApprovalBar" class="progress-bar bg-success" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
<p class="text-center mt-2 mb-0">
|
||||
Approval Rate: <span id="fgQualityApprovalRate" class="fw-bold">0%</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Export and Actions -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-download"></i> Export Options
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-outline-success" onclick="exportReportPDF()">
|
||||
<i class="fas fa-file-pdf"></i> Export PDF
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="exportReportExcel()">
|
||||
<i class="fas fa-file-excel"></i> Export Excel
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-info" onclick="printReport()">
|
||||
<i class="fas fa-print"></i> Print Report
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="shareReport()">
|
||||
<i class="fas fa-share"></i> Share Report
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div id="errorMessage" class="row mb-4" style="display: none;">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<strong>Error:</strong> <span id="errorText"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.metric-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1.5rem;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: 10px;
|
||||
margin-bottom: 1rem;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.metric-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.metric-card.orders-quantity {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
}
|
||||
|
||||
.metric-card.production-launched {
|
||||
background: linear-gradient(135deg, #f3e5f5 0%, #ce93d8 100%);
|
||||
}
|
||||
|
||||
.metric-card.production-finished {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #a5d6a7 100%);
|
||||
}
|
||||
|
||||
.metric-card.orders-delivered {
|
||||
background: linear-gradient(135deg, #fff3e0 0%, #ffcc02 100%);
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-right: 1rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.metric-content h3 {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.metric-content p {
|
||||
margin: 0;
|
||||
color: #6c757d;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.quality-stats .stat-item {
|
||||
text-align: center;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.quality-stats .stat-item h4 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.quality-stats .stat-item.approved h4 {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.quality-stats .stat-item.rejected h4 {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.quality-stats .stat-item p {
|
||||
margin: 0;
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.metric-card {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function setTodayDate() {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
document.getElementById('reportDate').value = today;
|
||||
generateDailyReport();
|
||||
}
|
||||
|
||||
function generateDailyReport() {
|
||||
const reportDate = document.getElementById('reportDate').value;
|
||||
|
||||
if (!reportDate) {
|
||||
showError('Please select a report date');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading indicator
|
||||
document.getElementById('loadingIndicator').style.display = 'block';
|
||||
document.getElementById('reportResults').style.display = 'none';
|
||||
document.getElementById('errorMessage').style.display = 'none';
|
||||
|
||||
// Make API call to get daily data
|
||||
fetch(`/daily_mirror/api/data?date=${reportDate}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
showError(data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update display with data
|
||||
updateDailyReport(data);
|
||||
|
||||
// Hide loading and show results
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
document.getElementById('reportResults').style.display = 'block';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error generating daily report:', error);
|
||||
showError('Failed to generate daily report. Please try again.');
|
||||
});
|
||||
}
|
||||
|
||||
function updateDailyReport(data) {
|
||||
// Update date display
|
||||
document.getElementById('reportDateDisplay').textContent = data.date;
|
||||
|
||||
// Update key metrics
|
||||
document.getElementById('ordersQuantity').textContent = data.orders_quantity.toLocaleString();
|
||||
document.getElementById('productionLaunched').textContent = data.production_launched.toLocaleString();
|
||||
document.getElementById('productionFinished').textContent = data.production_finished.toLocaleString();
|
||||
document.getElementById('ordersDelivered').textContent = data.orders_delivered.toLocaleString();
|
||||
|
||||
// Update quality control data
|
||||
document.getElementById('qualityTotalScans').textContent = data.quality_scans.total_scans.toLocaleString();
|
||||
document.getElementById('qualityApprovedScans').textContent = data.quality_scans.approved_scans.toLocaleString();
|
||||
document.getElementById('qualityRejectedScans').textContent = data.quality_scans.rejected_scans.toLocaleString();
|
||||
document.getElementById('qualityApprovalRate').textContent = data.quality_scans.approval_rate + '%';
|
||||
document.getElementById('qualityApprovalBar').style.width = data.quality_scans.approval_rate + '%';
|
||||
|
||||
// Update FG quality data
|
||||
document.getElementById('fgQualityTotalScans').textContent = data.fg_quality_scans.total_scans.toLocaleString();
|
||||
document.getElementById('fgQualityApprovedScans').textContent = data.fg_quality_scans.approved_scans.toLocaleString();
|
||||
document.getElementById('fgQualityRejectedScans').textContent = data.fg_quality_scans.rejected_scans.toLocaleString();
|
||||
document.getElementById('fgQualityApprovalRate').textContent = data.fg_quality_scans.approval_rate + '%';
|
||||
document.getElementById('fgQualityApprovalBar').style.width = data.fg_quality_scans.approval_rate + '%';
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
document.getElementById('errorText').textContent = message;
|
||||
document.getElementById('errorMessage').style.display = 'block';
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
document.getElementById('reportResults').style.display = 'none';
|
||||
}
|
||||
|
||||
function exportReportPDF() {
|
||||
alert('PDF export functionality will be implemented soon.');
|
||||
}
|
||||
|
||||
function exportReportExcel() {
|
||||
alert('Excel export functionality will be implemented soon.');
|
||||
}
|
||||
|
||||
function printReport() {
|
||||
window.print();
|
||||
}
|
||||
|
||||
function shareReport() {
|
||||
alert('Share functionality will be implemented soon.');
|
||||
}
|
||||
|
||||
// Auto-generate today's report on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
generateDailyReport();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,760 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Build Database - Daily Mirror{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='daily_mirror_tune.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Page Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">🔨 Build Database</h1>
|
||||
<p class="text-muted">Upload Excel files to populate Daily Mirror database tables</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<!-- Card 1: Upload Excel File -->
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-upload"></i> Upload Excel File
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data" id="uploadForm">
|
||||
<!-- Table Selection -->
|
||||
<div class="form-group mb-4">
|
||||
<label for="target_table" class="form-label">
|
||||
<strong>Select Target Table:</strong>
|
||||
</label>
|
||||
<select class="form-control" name="target_table" id="target_table" required>
|
||||
<option value="">-- Choose a table --</option>
|
||||
{% for table in available_tables %}
|
||||
<option value="{{ table.name }}" data-description="{{ table.description }}">
|
||||
{{ table.display }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<small id="tableDescription" class="form-text text-muted mt-2">
|
||||
Select a table to see its description.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- File Upload -->
|
||||
<div class="form-group mb-4">
|
||||
<label for="excel_file" class="form-label">
|
||||
<strong>Select Excel File:</strong>
|
||||
</label>
|
||||
<input type="file" class="form-control" name="excel_file" id="excel_file"
|
||||
accept=".xlsx,.xls" required>
|
||||
<small class="form-text text-muted">
|
||||
Accepted formats: .xlsx, .xls (Maximum file size: 10MB)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<div class="text-center">
|
||||
<button type="button" class="btn btn-primary btn-lg" id="uploadBtn">
|
||||
<i class="fas fa-cloud-upload-alt"></i> Upload and Process File
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 mb-4">
|
||||
<!-- Card 2: Excel File Format Instructions -->
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-info-circle"></i> Excel File Format Instructions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="accordion" id="formatAccordion">
|
||||
<!-- Production Data Format -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#productionCollapse" aria-expanded="false">
|
||||
🏭 Production Data Format
|
||||
</button>
|
||||
</h2>
|
||||
<div id="productionCollapse" class="accordion-collapse collapse" data-bs-parent="#formatAccordion">
|
||||
<div class="accordion-body">
|
||||
<p><strong>Expected columns for Production Data:</strong></p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li><code>Production Order ID</code> <span class="text-muted">Unique identifier</span></li>
|
||||
<li><code>Customer Code</code> <span class="text-muted">Customer code</span></li>
|
||||
<li><code>Customer Name</code> <span class="text-muted">Customer name</span></li>
|
||||
<li><code>Article Code</code> <span class="text-muted">Article code</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li><code>Article Description</code> <span class="text-muted">Description</span></li>
|
||||
<li><code>Quantity</code> <span class="text-muted">To produce</span></li>
|
||||
<li><code>Production Date</code> <span class="text-muted">Date</span></li>
|
||||
<li><code>Status</code> <span class="text-muted">Production status</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders Data Format -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#ordersCollapse" aria-expanded="false">
|
||||
🛒 Orders Data Format
|
||||
</button>
|
||||
</h2>
|
||||
<div id="ordersCollapse" class="accordion-collapse collapse" data-bs-parent="#formatAccordion">
|
||||
<div class="accordion-body">
|
||||
<p><strong>Expected columns for Orders Data:</strong></p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li><code>Order ID</code> <span class="text-muted">Unique identifier</span></li>
|
||||
<li><code>Customer Code</code> <span class="text-muted">Customer code</span></li>
|
||||
<li><code>Customer Name</code> <span class="text-muted">Customer name</span></li>
|
||||
<li><code>Article Code</code> <span class="text-muted">Article code</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li><code>Article Description</code> <span class="text-muted">Description</span></li>
|
||||
<li><code>Quantity Ordered</code> <span class="text-muted">Ordered</span></li>
|
||||
<li><code>Order Date</code> <span class="text-muted">Date</span></li>
|
||||
<li><code>Status</code> <span class="text-muted">Order status</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delivery Data Format -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#deliveryCollapse" aria-expanded="false">
|
||||
🚚 Delivery Data Format (Articole livrate)
|
||||
</button>
|
||||
</h2>
|
||||
<div id="deliveryCollapse" class="accordion-collapse collapse" data-bs-parent="#formatAccordion">
|
||||
<div class="accordion-body">
|
||||
<p><strong>Expected columns for Delivery Data:</strong></p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li><code>Shipment ID</code> <span class="text-muted">Unique shipment identifier</span></li>
|
||||
<li><code>Order ID</code> <span class="text-muted">Related order</span></li>
|
||||
<li><code>Customer</code> <span class="text-muted">Customer info</span></li>
|
||||
<li><code>Article</code> <span class="text-muted">Code/description</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li><code>Quantity Delivered</code> <span class="text-muted">Delivered quantity</span></li>
|
||||
<li><code>Delivery Date</code> <span class="text-muted">Date</span></li>
|
||||
<li><code>Status</code> <span class="text-muted">Delivery status</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Result Modal (Better Solution) -->
|
||||
<div class="modal fade" id="uploadResultModal" tabindex="-1" aria-labelledby="uploadResultModalLabel" aria-hidden="true" data-bs-backdrop="true" data-bs-keyboard="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" id="modalHeader">
|
||||
<h5 class="modal-title" id="uploadResultModalLabel">
|
||||
<i class="fas fa-check-circle"></i> Upload Result
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" id="modalCloseBtn"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="uploadResultContent" class="text-center py-3">
|
||||
<!-- Result content will be inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="modalOkBtn">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Additional modal fixes specific to this page */
|
||||
#uploadResultModal {
|
||||
z-index: 10000 !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
#uploadResultModal .modal-dialog {
|
||||
pointer-events: auto !important;
|
||||
z-index: 10001 !important;
|
||||
}
|
||||
|
||||
#uploadResultModal .modal-content {
|
||||
pointer-events: auto !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
#uploadResultModal .modal-backdrop {
|
||||
z-index: 9998 !important;
|
||||
}
|
||||
|
||||
#uploadResultModal .btn-close,
|
||||
#uploadResultModal .modal-footer button {
|
||||
pointer-events: auto !important;
|
||||
cursor: pointer !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* Ensure modal can be dismissed */
|
||||
.modal-backdrop.show {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* Dark mode modal fixes */
|
||||
body.dark-mode #uploadResultModal .modal-content {
|
||||
background-color: #2d3748 !important;
|
||||
}
|
||||
|
||||
.accordion-button:not(.collapsed) {
|
||||
background-color: #e7f3ff;
|
||||
color: #0066cc;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #007bff;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
|
||||
}
|
||||
|
||||
/* Result stats styling */
|
||||
.upload-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.stat-box {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
min-width: 100px;
|
||||
margin: 5px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stat-box.success {
|
||||
background-color: #d4edda;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.stat-box.warning {
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeeba;
|
||||
}
|
||||
|
||||
.stat-box.error {
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* Reduce font size for Excel Format Instructions card rows */
|
||||
.col-lg-6:nth-child(2) .card-body {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* Make accordion button labels smaller */
|
||||
.accordion-button {
|
||||
font-size: 1rem;
|
||||
padding-top: 0.4rem;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
/* Override h2 size in accordion headers */
|
||||
.accordion-header {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.accordion-header h2 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Modal summary list styling */
|
||||
#uploadResultContent ul {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
margin: 10px auto;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#uploadResultContent ul li {
|
||||
padding: 5px 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
#uploadResultContent ul li::before {
|
||||
content: '✓ ';
|
||||
color: #28a745;
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Make "Expected columns" text smaller in accordion bodies */
|
||||
.accordion-body p {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.accordion-body strong {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Dark mode styles */
|
||||
body.dark-mode .card {
|
||||
background-color: #2d3748;
|
||||
border-color: #4a5568;
|
||||
color: #e2e8f0;
|
||||
box-shadow: 0 4px 6px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
body.dark-mode .card-header {
|
||||
background-color: #4a5568;
|
||||
color: #e2e8f0;
|
||||
border-bottom: 1px solid rgba(226, 232, 240, 0.2);
|
||||
}
|
||||
|
||||
body.dark-mode .form-control {
|
||||
background-color: #4a5568;
|
||||
border-color: #6b7280;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .form-control:focus {
|
||||
background-color: #4a5568;
|
||||
border-color: #007bff;
|
||||
color: #e2e8f0;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
||||
body.dark-mode .accordion-button {
|
||||
background-color: #374151;
|
||||
color: #e2e8f0;
|
||||
border-color: #6b7280;
|
||||
}
|
||||
|
||||
body.dark-mode .accordion-button:not(.collapsed) {
|
||||
background-color: #1e3a8a;
|
||||
color: #bfdbfe;
|
||||
}
|
||||
|
||||
body.dark-mode .accordion-body {
|
||||
background-color: #374151;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode code {
|
||||
background-color: #374151;
|
||||
color: #e2e8f0;
|
||||
border: 1px solid #6b7280;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-content {
|
||||
background-color: #2d3748;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-header {
|
||||
border-bottom-color: #4a5568;
|
||||
}
|
||||
|
||||
body.dark-mode .modal-footer {
|
||||
border-top-color: #4a5568;
|
||||
}
|
||||
|
||||
body.dark-mode .stat-box.success {
|
||||
background-color: #1e4620;
|
||||
border-color: #2d5a2e;
|
||||
color: #a3d9a5;
|
||||
}
|
||||
|
||||
body.dark-mode .stat-box.warning {
|
||||
background-color: #5a4a1e;
|
||||
border-color: #6b5a2d;
|
||||
color: #f4d88f;
|
||||
}
|
||||
|
||||
body.dark-mode .stat-box.error {
|
||||
background-color: #5a1e1e;
|
||||
border-color: #6b2d2d;
|
||||
color: #f8a3a8;
|
||||
}
|
||||
|
||||
body.dark-mode .stat-label {
|
||||
color: #a0aec0;
|
||||
}
|
||||
|
||||
body.dark-mode .text-muted {
|
||||
color: #a0aec0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize theme on page load
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const body = document.body;
|
||||
|
||||
if (savedTheme === 'dark') {
|
||||
body.classList.add('dark-mode');
|
||||
} else {
|
||||
body.classList.remove('dark-mode');
|
||||
}
|
||||
|
||||
const tableSelect = document.getElementById('target_table');
|
||||
const tableDescription = document.getElementById('tableDescription');
|
||||
const uploadBtn = document.getElementById('uploadBtn');
|
||||
const uploadForm = document.getElementById('uploadForm');
|
||||
const fileInput = document.getElementById('excel_file');
|
||||
|
||||
// Update table description when selection changes
|
||||
tableSelect.addEventListener('change', function() {
|
||||
const selectedOption = this.options[this.selectedIndex];
|
||||
if (selectedOption.value) {
|
||||
const description = selectedOption.getAttribute('data-description');
|
||||
tableDescription.innerHTML = `<strong>Selected:</strong> ${description}`;
|
||||
tableDescription.className = 'form-text text-info mt-2';
|
||||
} else {
|
||||
tableDescription.innerHTML = 'Select a table to see its description.';
|
||||
tableDescription.className = 'form-text text-muted mt-2';
|
||||
}
|
||||
});
|
||||
|
||||
// File input change handler to show file info
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
const fileName = file.name;
|
||||
const fileSize = (file.size / 1024 / 1024).toFixed(2);
|
||||
console.log(`Selected file: ${fileName} (${fileSize} MB)`);
|
||||
}
|
||||
});
|
||||
|
||||
// Upload button click handler (AJAX submission)
|
||||
uploadBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Validate file selection
|
||||
if (!fileInput.files.length) {
|
||||
alert('Please select an Excel file to upload.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate table selection
|
||||
if (!tableSelect.value) {
|
||||
alert('Please select a target table.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check file size (10MB limit)
|
||||
const file = fileInput.files[0];
|
||||
if (file.size > 10 * 1024 * 1024) {
|
||||
alert('File size must be less than 10MB.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare form data
|
||||
const formData = new FormData(uploadForm);
|
||||
|
||||
// Show loading state
|
||||
uploadBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Processing...';
|
||||
uploadBtn.disabled = true;
|
||||
|
||||
// Submit via AJAX
|
||||
fetch('/daily_mirror/build_database', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
return response.json().then(err => Promise.reject(err));
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(result => {
|
||||
// Reset button
|
||||
uploadBtn.innerHTML = '<i class="fas fa-cloud-upload-alt"></i> Upload and Process File';
|
||||
uploadBtn.disabled = false;
|
||||
|
||||
// Show result in modal
|
||||
showUploadResult(result);
|
||||
|
||||
// Reset form
|
||||
uploadForm.reset();
|
||||
tableDescription.innerHTML = 'Select a table to see its description.';
|
||||
tableDescription.className = 'form-text text-muted mt-2';
|
||||
})
|
||||
.catch(error => {
|
||||
// Reset button
|
||||
uploadBtn.innerHTML = '<i class="fas fa-cloud-upload-alt"></i> Upload and Process File';
|
||||
uploadBtn.disabled = false;
|
||||
|
||||
// Show error in modal
|
||||
showUploadError(error);
|
||||
});
|
||||
});
|
||||
|
||||
function showUploadResult(result) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('uploadResultModal'));
|
||||
const modalHeader = document.getElementById('modalHeader');
|
||||
const modalTitle = document.getElementById('uploadResultModalLabel');
|
||||
const content = document.getElementById('uploadResultContent');
|
||||
|
||||
// Determine overall status
|
||||
const hasErrors = result.error_count && result.error_count > 0;
|
||||
const hasSuccess = result.created_rows > 0 || result.updated_rows > 0;
|
||||
|
||||
// Update modal header color
|
||||
if (hasErrors && !hasSuccess) {
|
||||
modalHeader.className = 'modal-header bg-danger text-white';
|
||||
modalTitle.innerHTML = '<i class="fas fa-times-circle"></i> Upload Failed';
|
||||
} else if (hasErrors && hasSuccess) {
|
||||
modalHeader.className = 'modal-header bg-warning text-dark';
|
||||
modalTitle.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Upload Completed with Warnings';
|
||||
} else {
|
||||
modalHeader.className = 'modal-header bg-success text-white';
|
||||
modalTitle.innerHTML = '<i class="fas fa-check-circle"></i> Upload Successful';
|
||||
}
|
||||
|
||||
// Build result content with stats
|
||||
let html = '<div class="upload-stats">';
|
||||
|
||||
// Total rows processed from Excel
|
||||
html += `
|
||||
<div class="stat-box ${hasErrors ? 'warning' : 'success'}">
|
||||
<span class="stat-value">${result.total_rows || 0}</span>
|
||||
<span class="stat-label">Rows Processed</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Created rows (new in database)
|
||||
if (result.created_rows > 0) {
|
||||
html += `
|
||||
<div class="stat-box success">
|
||||
<span class="stat-value">${result.created_rows}</span>
|
||||
<span class="stat-label">New Rows Created</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Updated rows (existing in database)
|
||||
if (result.updated_rows > 0) {
|
||||
html += `
|
||||
<div class="stat-box success">
|
||||
<span class="stat-value">${result.updated_rows}</span>
|
||||
<span class="stat-label">Rows Updated</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Errors
|
||||
if (hasErrors) {
|
||||
html += `
|
||||
<div class="stat-box error">
|
||||
<span class="stat-value">${result.error_count}</span>
|
||||
<span class="stat-label">Errors</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
// Add detailed summary message
|
||||
const successCount = (result.created_rows || 0) + (result.updated_rows || 0);
|
||||
if (successCount > 0) {
|
||||
let msg = `<p class="mt-3 mb-0"><strong>Successfully processed ${result.total_rows} rows from Excel:</strong></p>`;
|
||||
msg += '<ul class="text-start">';
|
||||
if (result.created_rows > 0) {
|
||||
msg += `<li>${result.created_rows} new ${result.created_rows === 1 ? 'record' : 'records'} created in database</li>`;
|
||||
}
|
||||
if (result.updated_rows > 0) {
|
||||
msg += `<li>${result.updated_rows} existing ${result.updated_rows === 1 ? 'record' : 'records'} updated</li>`;
|
||||
}
|
||||
msg += '</ul>';
|
||||
html += msg;
|
||||
}
|
||||
if (hasErrors) {
|
||||
html += `<p class="text-danger mb-0"><strong>⚠️ ${result.error_count} ${result.error_count === 1 ? 'row' : 'rows'} could not be processed due to errors.</strong></p>`;
|
||||
}
|
||||
|
||||
// Add auto-close countdown for successful uploads without errors
|
||||
if (!hasErrors && successCount > 0) {
|
||||
html += `<p class="text-muted mt-2 mb-0" id="autoCloseCountdown"><small>This window will close automatically in <span id="countdown">3</span> seconds...</small></p>`;
|
||||
}
|
||||
|
||||
content.innerHTML = html;
|
||||
modal.show();
|
||||
|
||||
// Get modal element
|
||||
const modalElement = document.getElementById('uploadResultModal');
|
||||
|
||||
// Add explicit close handlers
|
||||
const okBtn = document.getElementById('modalOkBtn');
|
||||
const closeBtn = document.getElementById('modalCloseBtn');
|
||||
|
||||
if (okBtn) {
|
||||
okBtn.onclick = function() {
|
||||
modal.hide();
|
||||
// Also trigger Bootstrap's native close
|
||||
modalElement.classList.remove('show');
|
||||
document.querySelector('.modal-backdrop')?.remove();
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.paddingRight = '';
|
||||
};
|
||||
}
|
||||
|
||||
if (closeBtn) {
|
||||
closeBtn.onclick = function() {
|
||||
modal.hide();
|
||||
// Also trigger Bootstrap's native close
|
||||
modalElement.classList.remove('show');
|
||||
document.querySelector('.modal-backdrop')?.remove();
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.paddingRight = '';
|
||||
};
|
||||
}
|
||||
|
||||
// Auto-close after 3 seconds for successful uploads without errors
|
||||
if (!hasErrors && successCount > 0) {
|
||||
let countdown = 3;
|
||||
const countdownInterval = setInterval(function() {
|
||||
countdown--;
|
||||
const countdownSpan = document.getElementById('countdown');
|
||||
if (countdownSpan) {
|
||||
countdownSpan.textContent = countdown;
|
||||
}
|
||||
if (countdown <= 0) {
|
||||
clearInterval(countdownInterval);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
setTimeout(function() {
|
||||
clearInterval(countdownInterval);
|
||||
modal.hide();
|
||||
modalElement.classList.remove('show');
|
||||
document.querySelector('.modal-backdrop')?.remove();
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.paddingRight = '';
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
function showUploadError(error) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('uploadResultModal'));
|
||||
const modalHeader = document.getElementById('modalHeader');
|
||||
const modalTitle = document.getElementById('uploadResultModalLabel');
|
||||
const content = document.getElementById('uploadResultContent');
|
||||
|
||||
// Update modal header
|
||||
modalHeader.className = 'modal-header bg-danger text-white';
|
||||
modalTitle.innerHTML = '<i class="fas fa-times-circle"></i> Upload Error';
|
||||
|
||||
// Show error message
|
||||
const errorMsg = error.error || error.message || 'An unexpected error occurred during upload.';
|
||||
content.innerHTML = `
|
||||
<div class="alert alert-danger mb-0">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<strong>Error:</strong> ${errorMsg}
|
||||
</div>
|
||||
`;
|
||||
|
||||
modal.show();
|
||||
|
||||
// Get modal element
|
||||
const modalElement = document.getElementById('uploadResultModal');
|
||||
|
||||
// Add explicit close handlers
|
||||
const okBtn = document.getElementById('modalOkBtn');
|
||||
const closeBtn = document.getElementById('modalCloseBtn');
|
||||
|
||||
if (okBtn) {
|
||||
okBtn.onclick = function() {
|
||||
modal.hide();
|
||||
// Also trigger Bootstrap's native close
|
||||
modalElement.classList.remove('show');
|
||||
document.querySelector('.modal-backdrop')?.remove();
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.paddingRight = '';
|
||||
};
|
||||
}
|
||||
|
||||
if (closeBtn) {
|
||||
closeBtn.onclick = function() {
|
||||
modal.hide();
|
||||
// Also trigger Bootstrap's native close
|
||||
modalElement.classList.remove('show');
|
||||
document.querySelector('.modal-backdrop')?.remove();
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.paddingRight = '';
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,449 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Daily Mirror History - Quality Recticel{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Page Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">📋 Daily Mirror History</h1>
|
||||
<p class="text-muted">Analyze historical daily production reports and trends</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ url_for('daily_mirror.daily_mirror_route') }}" class="btn btn-outline-success">
|
||||
<i class="fas fa-chart-line"></i> Create New Report
|
||||
</a>
|
||||
<a href="{{ url_for('main.dashboard') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date Range Selection -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-calendar-week"></i> Select Date Range
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<label for="startDate" class="form-label">Start Date:</label>
|
||||
<input type="date" class="form-control" id="startDate" value="{{ start_date }}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="endDate" class="form-label">End Date:</label>
|
||||
<input type="date" class="form-control" id="endDate" value="{{ end_date }}">
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-primary" onclick="loadHistoryData()">
|
||||
<i class="fas fa-search"></i> Load History
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="setDateRange(7)">Last 7 days</button>
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="setDateRange(30)">Last 30 days</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<div id="loadingIndicator" class="row mb-4" style="display: none;">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2 mb-0">Loading historical data...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary Statistics -->
|
||||
<div id="summaryStats" style="display: none;">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-chart-bar"></i> Period Summary
|
||||
<span id="periodRange" class="badge bg-secondary ms-2"></span>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="summary-metric">
|
||||
<h4 id="totalOrdersQuantity">-</h4>
|
||||
<p>Total Orders Quantity</p>
|
||||
<small id="avgOrdersQuantity" class="text-muted">Avg: -</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="summary-metric">
|
||||
<h4 id="totalProductionLaunched">-</h4>
|
||||
<p>Total Production Launched</p>
|
||||
<small id="avgProductionLaunched" class="text-muted">Avg: -</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="summary-metric">
|
||||
<h4 id="totalProductionFinished">-</h4>
|
||||
<p>Total Production Finished</p>
|
||||
<small id="avgProductionFinished" class="text-muted">Avg: -</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="summary-metric">
|
||||
<h4 id="totalOrdersDelivered">-</h4>
|
||||
<p>Total Orders Delivered</p>
|
||||
<small id="avgOrdersDelivered" class="text-muted">Avg: -</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Historical Data Table -->
|
||||
<div id="historyTable" style="display: none;">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-table"></i> Historical Daily Reports
|
||||
</h5>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="exportHistoryCSV()">
|
||||
<i class="fas fa-file-csv"></i> CSV
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-success" onclick="exportHistoryExcel()">
|
||||
<i class="fas fa-file-excel"></i> Excel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="historyDataTable">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Orders Quantity</th>
|
||||
<th>Production Launched</th>
|
||||
<th>Production Finished</th>
|
||||
<th>Orders Delivered</th>
|
||||
<th>Quality Approval Rate</th>
|
||||
<th>FG Quality Approval Rate</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="historyTableBody">
|
||||
<!-- Data will be populated here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav aria-label="History pagination" id="historyPagination" style="display: none;">
|
||||
<ul class="pagination pagination-sm justify-content-center">
|
||||
<!-- Pagination will be populated here -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chart Visualization -->
|
||||
<div id="chartVisualization" style="display: none;">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-chart-line"></i> Trend Analysis
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="trendChart" height="100"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div id="errorMessage" class="row mb-4" style="display: none;">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<strong>Error:</strong> <span id="errorText"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.summary-metric {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.summary-metric h4 {
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.summary-metric p {
|
||||
margin: 0.5rem 0;
|
||||
color: #6c757d;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.table th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.approval-rate {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.approval-rate.high {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.approval-rate.medium {
|
||||
color: #ffc107;
|
||||
}
|
||||
|
||||
.approval-rate.low {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.table-responsive {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let historyData = [];
|
||||
let currentPage = 1;
|
||||
const itemsPerPage = 20;
|
||||
|
||||
function setDateRange(days) {
|
||||
const endDate = new Date();
|
||||
const startDate = new Date();
|
||||
startDate.setDate(endDate.getDate() - days);
|
||||
|
||||
document.getElementById('endDate').value = endDate.toISOString().split('T')[0];
|
||||
document.getElementById('startDate').value = startDate.toISOString().split('T')[0];
|
||||
|
||||
loadHistoryData();
|
||||
}
|
||||
|
||||
function loadHistoryData() {
|
||||
const startDate = document.getElementById('startDate').value;
|
||||
const endDate = document.getElementById('endDate').value;
|
||||
|
||||
if (!startDate || !endDate) {
|
||||
showError('Please select both start and end dates');
|
||||
return;
|
||||
}
|
||||
|
||||
if (new Date(startDate) > new Date(endDate)) {
|
||||
showError('Start date cannot be after end date');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading indicator
|
||||
document.getElementById('loadingIndicator').style.display = 'block';
|
||||
document.getElementById('summaryStats').style.display = 'none';
|
||||
document.getElementById('historyTable').style.display = 'none';
|
||||
document.getElementById('chartVisualization').style.display = 'none';
|
||||
document.getElementById('errorMessage').style.display = 'none';
|
||||
|
||||
// Make API call to get historical data
|
||||
fetch(`/daily_mirror/api/history_data?start_date=${startDate}&end_date=${endDate}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
showError(data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
historyData = data.history;
|
||||
|
||||
// Update displays
|
||||
updateSummaryStats(data);
|
||||
updateHistoryTable();
|
||||
updateTrendChart();
|
||||
|
||||
// Hide loading and show results
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
document.getElementById('summaryStats').style.display = 'block';
|
||||
document.getElementById('historyTable').style.display = 'block';
|
||||
document.getElementById('chartVisualization').style.display = 'block';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading history data:', error);
|
||||
showError('Failed to load historical data. Please try again.');
|
||||
});
|
||||
}
|
||||
|
||||
function updateSummaryStats(data) {
|
||||
const history = data.history;
|
||||
|
||||
if (history.length === 0) {
|
||||
document.getElementById('periodRange').textContent = 'No Data';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('periodRange').textContent = `${data.start_date} to ${data.end_date}`;
|
||||
|
||||
// Calculate totals and averages
|
||||
const totals = history.reduce((acc, day) => {
|
||||
acc.ordersQuantity += day.orders_quantity;
|
||||
acc.productionLaunched += day.production_launched;
|
||||
acc.productionFinished += day.production_finished;
|
||||
acc.ordersDelivered += day.orders_delivered;
|
||||
return acc;
|
||||
}, { ordersQuantity: 0, productionLaunched: 0, productionFinished: 0, ordersDelivered: 0 });
|
||||
|
||||
const avgDivisor = history.length;
|
||||
|
||||
document.getElementById('totalOrdersQuantity').textContent = totals.ordersQuantity.toLocaleString();
|
||||
document.getElementById('avgOrdersQuantity').textContent = `Avg: ${Math.round(totals.ordersQuantity / avgDivisor).toLocaleString()}`;
|
||||
|
||||
document.getElementById('totalProductionLaunched').textContent = totals.productionLaunched.toLocaleString();
|
||||
document.getElementById('avgProductionLaunched').textContent = `Avg: ${Math.round(totals.productionLaunched / avgDivisor).toLocaleString()}`;
|
||||
|
||||
document.getElementById('totalProductionFinished').textContent = totals.productionFinished.toLocaleString();
|
||||
document.getElementById('avgProductionFinished').textContent = `Avg: ${Math.round(totals.productionFinished / avgDivisor).toLocaleString()}`;
|
||||
|
||||
document.getElementById('totalOrdersDelivered').textContent = totals.ordersDelivered.toLocaleString();
|
||||
document.getElementById('avgOrdersDelivered').textContent = `Avg: ${Math.round(totals.ordersDelivered / avgDivisor).toLocaleString()}`;
|
||||
}
|
||||
|
||||
function updateHistoryTable() {
|
||||
const tbody = document.getElementById('historyTableBody');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
const startIndex = (currentPage - 1) * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
const pageData = historyData.slice(startIndex, endIndex);
|
||||
|
||||
pageData.forEach(day => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
const qualityRate = day.quality_scans.approval_rate;
|
||||
const fgQualityRate = day.fg_quality_scans.approval_rate;
|
||||
|
||||
row.innerHTML = `
|
||||
<td><strong>${day.date}</strong></td>
|
||||
<td>${day.orders_quantity.toLocaleString()}</td>
|
||||
<td>${day.production_launched.toLocaleString()}</td>
|
||||
<td>${day.production_finished.toLocaleString()}</td>
|
||||
<td>${day.orders_delivered.toLocaleString()}</td>
|
||||
<td><span class="approval-rate ${getApprovalRateClass(qualityRate)}">${qualityRate}%</span></td>
|
||||
<td><span class="approval-rate ${getApprovalRateClass(fgQualityRate)}">${fgQualityRate}%</span></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="viewDayDetails('${day.date}')">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
|
||||
updatePagination();
|
||||
}
|
||||
|
||||
function getApprovalRateClass(rate) {
|
||||
if (rate >= 95) return 'high';
|
||||
if (rate >= 85) return 'medium';
|
||||
return 'low';
|
||||
}
|
||||
|
||||
function updatePagination() {
|
||||
const totalPages = Math.ceil(historyData.length / itemsPerPage);
|
||||
|
||||
if (totalPages <= 1) {
|
||||
document.getElementById('historyPagination').style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('historyPagination').style.display = 'block';
|
||||
// Pagination implementation can be added here
|
||||
}
|
||||
|
||||
function updateTrendChart() {
|
||||
// Chart implementation using Chart.js can be added here
|
||||
// For now, we'll show a placeholder
|
||||
const canvas = document.getElementById('trendChart');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Clear canvas
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Draw placeholder text
|
||||
ctx.font = '16px Arial';
|
||||
ctx.fillStyle = '#6c757d';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('Trend chart visualization will be implemented here', canvas.width / 2, canvas.height / 2);
|
||||
}
|
||||
|
||||
function viewDayDetails(date) {
|
||||
// Navigate to daily mirror with specific date
|
||||
window.open(`{{ url_for('daily_mirror.daily_mirror_route') }}?date=${date}`, '_blank');
|
||||
}
|
||||
|
||||
function exportHistoryCSV() {
|
||||
alert('CSV export functionality will be implemented soon.');
|
||||
}
|
||||
|
||||
function exportHistoryExcel() {
|
||||
alert('Excel export functionality will be implemented soon.');
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
document.getElementById('errorText').textContent = message;
|
||||
document.getElementById('errorMessage').style.display = 'block';
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
document.getElementById('summaryStats').style.display = 'none';
|
||||
document.getElementById('historyTable').style.display = 'none';
|
||||
document.getElementById('chartVisualization').style.display = 'none';
|
||||
}
|
||||
|
||||
// Auto-load data on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadHistoryData();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,262 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Daily Mirror - Quality Recticel{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Page Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">📊 Daily Mirror</h1>
|
||||
<p class="text-muted">Business Intelligence and Production Reporting</p>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Buttons removed; now present in top header -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Daily Mirror Cards -->
|
||||
<div class="row">
|
||||
<!-- Card 1: Build Database -->
|
||||
<div class="col-lg-6 col-md-6 mb-4">
|
||||
<div class="card h-100 daily-mirror-card">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="text-center mb-3">
|
||||
<div class="feature-icon bg-primary">
|
||||
<i class="fas fa-database"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="card-title text-center">Build Database</h5>
|
||||
<p class="card-text flex-grow-1 text-center">
|
||||
Upload Excel files to create and populate tables.
|
||||
</p>
|
||||
<div class="mt-auto">
|
||||
<a href="{{ url_for('daily_mirror.daily_mirror_build_database') }}" class="btn btn-primary btn-block w-100">
|
||||
<i class="fas fa-hammer"></i> Build Database
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 2: Tune Database -->
|
||||
<div class="col-lg-6 col-md-6 mb-4">
|
||||
<div class="card h-100 daily-mirror-card">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="text-center mb-3">
|
||||
<div class="feature-icon bg-warning">
|
||||
<i class="fas fa-edit"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="card-title text-center">Tune Database</h5>
|
||||
<p class="card-text flex-grow-1 text-center">
|
||||
Edit and update records after import.
|
||||
</p>
|
||||
<div class="mt-auto">
|
||||
<a href="{{ url_for('daily_mirror.tune_production_data') }}" class="btn btn-warning btn-block w-100 btn-sm mb-2">
|
||||
<i class="fas fa-industry"></i> Production Orders
|
||||
</a>
|
||||
<a href="{{ url_for('daily_mirror.tune_orders_data') }}" class="btn btn-warning btn-block w-100 btn-sm mb-2">
|
||||
<i class="fas fa-shopping-cart"></i> Customer Orders
|
||||
</a>
|
||||
<a href="{{ url_for('daily_mirror.tune_delivery_data') }}" class="btn btn-warning btn-block w-100 btn-sm">
|
||||
<i class="fas fa-truck"></i> Delivery Records
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 3: Daily Mirror -->
|
||||
<div class="col-lg-6 col-md-6 mb-4">
|
||||
<div class="card h-100 daily-mirror-card">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="text-center mb-3">
|
||||
<div class="feature-icon bg-success">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="card-title text-center">Daily Mirror</h5>
|
||||
<p class="card-text flex-grow-1 text-center">
|
||||
Generate daily production reports.
|
||||
</p>
|
||||
<div class="mt-auto">
|
||||
<a href="{{ url_for('daily_mirror.daily_mirror_route') }}" class="btn btn-success btn-block w-100">
|
||||
<i class="fas fa-plus-circle"></i> Create Daily Report
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 4: Daily Mirror History -->
|
||||
<div class="col-lg-6 col-md-6 mb-4">
|
||||
<div class="card h-100 daily-mirror-card">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="text-center mb-3">
|
||||
<div class="feature-icon bg-info">
|
||||
<i class="fas fa-history"></i>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="card-title text-center">Daily Mirror History</h5>
|
||||
<p class="card-text flex-grow-1 text-center">
|
||||
View historical production reports.
|
||||
</p>
|
||||
<div class="mt-auto">
|
||||
<a href="{{ url_for('daily_mirror.daily_mirror_history_route') }}" class="btn btn-info btn-block w-100">
|
||||
<i class="fas fa-chart-bar"></i> View History
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.daily-mirror-card {
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
border: none;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
background-color: var(--card-bg);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.daily-mirror-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
color: white;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
/* Light mode styles */
|
||||
body:not(.dark-mode) .daily-mirror-card {
|
||||
background-color: #ffffff;
|
||||
color: #333333;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
body:not(.dark-mode) .card-text {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
body:not(.dark-mode) .text-muted {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
/* Dark mode styles */
|
||||
body.dark-mode .daily-mirror-card {
|
||||
background-color: #2d3748;
|
||||
color: #e2e8f0;
|
||||
border: 1px solid #4a5568;
|
||||
box-shadow: 0 2px 4px rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
body.dark-mode .daily-mirror-card:hover {
|
||||
box-shadow: 0 4px 15px rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
body.dark-mode .card-text {
|
||||
color: #cbd5e0;
|
||||
}
|
||||
|
||||
body.dark-mode .text-muted {
|
||||
color: #a0aec0 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .h3 {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .container-fluid {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
/* Ensure buttons maintain their intended colors in both themes */
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: linear-gradient(135deg, #ffc107 0%, #e0a800 100%);
|
||||
border: none;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: linear-gradient(135deg, #28a745 0%, #1e7e34 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: linear-gradient(135deg, #6c757d 0%, #545b62 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.feature-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}</style>
|
||||
|
||||
<script>
|
||||
// Initialize theme on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Apply saved theme from localStorage
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
const body = document.body;
|
||||
|
||||
if (savedTheme === 'dark') {
|
||||
body.classList.add('dark-mode');
|
||||
} else {
|
||||
body.classList.remove('dark-mode');
|
||||
}
|
||||
|
||||
// Update theme toggle button text if it exists
|
||||
const themeToggleButton = document.getElementById('theme-toggle');
|
||||
if (themeToggleButton) {
|
||||
if (body.classList.contains('dark-mode')) {
|
||||
themeToggleButton.textContent = 'Change to Light Mode';
|
||||
} else {
|
||||
themeToggleButton.textContent = 'Change to Dark Mode';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function showComingSoon(feature) {
|
||||
alert(`${feature} functionality will be available in a future update!\n\nThis feature is currently under development and will include advanced capabilities for enhanced Daily Mirror operations.`);
|
||||
}
|
||||
|
||||
// Auto-refresh quick stats every 5 minutes
|
||||
setInterval(function() {
|
||||
// This could be implemented to refresh the quick stats
|
||||
console.log('Auto-refresh daily stats (not implemented yet)');
|
||||
}, 300000); // 5 minutes
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,549 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Tune Delivery Data - Daily Mirror{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/daily_mirror_tune.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Page Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">🚚 Tune Delivery Data</h1>
|
||||
<p class="text-muted">Edit and update delivery records information</p>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Buttons removed; now present in top header -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters Section -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-filter"></i> Filters and Search
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="searchInput" class="form-label">Search</label>
|
||||
<input type="text" class="form-control" id="searchInput"
|
||||
placeholder="Search by shipment, customer, or article...">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="statusFilter" class="form-label">Delivery Status</label>
|
||||
<select class="form-control" id="statusFilter">
|
||||
<option value="">All Statuses</option>
|
||||
<!-- Will be populated dynamically -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="customerFilter" class="form-label">Customer</label>
|
||||
<select class="form-control" id="customerFilter">
|
||||
<option value="">All Customers</option>
|
||||
<!-- Will be populated dynamically -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="recordsPerPage" class="form-label">Records per page</label>
|
||||
<select class="form-control" id="recordsPerPage">
|
||||
<option value="25">25</option>
|
||||
<option value="50" selected>50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button class="btn btn-primary" onclick="loadDeliveryData()">
|
||||
<i class="fas fa-search"></i> Apply Filters
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="clearFilters()">
|
||||
<i class="fas fa-times"></i> Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Table Section -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-table"></i> Delivery Records Data
|
||||
</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<span id="recordsInfo" class="text-muted me-3"></span>
|
||||
{% if session.get('role') == 'superadmin' %}
|
||||
<button class="btn btn-danger btn-sm me-2" onclick="clearAllDelivery()" id="clearAllBtn">
|
||||
<i class="fas fa-trash-alt"></i> Clear All Delivery
|
||||
</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-success btn-sm" onclick="saveAllChanges()">
|
||||
<i class="fas fa-save"></i> Save All Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="deliveryTable">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Shipment ID</th>
|
||||
<th>Customer</th>
|
||||
<th>Order ID</th>
|
||||
<th>Article Code</th>
|
||||
<th>Description</th>
|
||||
<th>Quantity</th>
|
||||
<th>Shipment Date</th>
|
||||
<th>Delivery Date</th>
|
||||
<th>Status</th>
|
||||
<th>Total Value</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="deliveryTableBody">
|
||||
<!-- Data will be loaded here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Loading indicator -->
|
||||
<div id="loadingIndicator" class="text-center py-4" style="display: none;">
|
||||
<i class="fas fa-spinner fa-spin fa-2x"></i>
|
||||
<p class="mt-2">Loading data...</p>
|
||||
</div>
|
||||
|
||||
<!-- No data message -->
|
||||
<div id="noDataMessage" class="text-center py-4" style="display: none;">
|
||||
<i class="fas fa-info-circle fa-2x text-muted"></i>
|
||||
<p class="mt-2 text-muted">No delivery records found</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="card-footer">
|
||||
<nav aria-label="Delivery data pagination">
|
||||
<ul class="pagination pagination-sm justify-content-center mb-0" id="pagination">
|
||||
<!-- Pagination will be generated here -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit Modal -->
|
||||
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editModalLabel">Edit Delivery Record</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editForm">
|
||||
<input type="hidden" id="editRecordId">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editShipmentId" class="form-label">Shipment ID</label>
|
||||
<input type="text" class="form-control" id="editShipmentId" readonly>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editOrderId" class="form-label">Order ID</label>
|
||||
<input type="text" class="form-control" id="editOrderId">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editCustomerCode" class="form-label">Customer Code</label>
|
||||
<input type="text" class="form-control" id="editCustomerCode">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editCustomerName" class="form-label">Customer Name</label>
|
||||
<input type="text" class="form-control" id="editCustomerName">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editArticleCode" class="form-label">Article Code</label>
|
||||
<input type="text" class="form-control" id="editArticleCode">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editQuantity" class="form-label">Quantity Delivered</label>
|
||||
<input type="number" class="form-control" id="editQuantity">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editDescription" class="form-label">Article Description</label>
|
||||
<textarea class="form-control" id="editDescription" rows="2"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editShipmentDate" class="form-label">Shipment Date</label>
|
||||
<input type="date" class="form-control" id="editShipmentDate">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editDeliveryDate" class="form-label">Delivery Date</label>
|
||||
<input type="date" class="form-control" id="editDeliveryDate">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editDeliveryStatus" class="form-label">Delivery Status</label>
|
||||
<select class="form-control" id="editDeliveryStatus">
|
||||
<option value="Finalizat">Finalizat</option>
|
||||
<option value="Proiect">Proiect</option>
|
||||
<option value="SHIPPED">Shipped</option>
|
||||
<option value="DELIVERED">Delivered</option>
|
||||
<option value="RETURNED">Returned</option>
|
||||
<option value="PARTIAL">Partial</option>
|
||||
<option value="CANCELLED">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="editTotalValue" class="form-label">Total Value (€)</label>
|
||||
<input type="number" step="0.01" class="form-control" id="editTotalValue">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="fas fa-times"></i> Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveRecord()">
|
||||
<i class="fas fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentPage = 1;
|
||||
let currentPerPage = 50;
|
||||
let currentSearch = '';
|
||||
let currentStatusFilter = '';
|
||||
let currentCustomerFilter = '';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize theme
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
|
||||
// Load initial data
|
||||
loadDeliveryData();
|
||||
|
||||
// Setup search on enter key
|
||||
document.getElementById('searchInput').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
loadDeliveryData();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function loadDeliveryData(page = 1) {
|
||||
currentPage = page;
|
||||
currentPerPage = document.getElementById('recordsPerPage').value;
|
||||
currentSearch = document.getElementById('searchInput').value;
|
||||
currentStatusFilter = document.getElementById('statusFilter').value;
|
||||
currentCustomerFilter = document.getElementById('customerFilter').value;
|
||||
|
||||
// Show loading indicator
|
||||
document.getElementById('loadingIndicator').style.display = 'block';
|
||||
document.getElementById('deliveryTableBody').style.display = 'none';
|
||||
document.getElementById('noDataMessage').style.display = 'none';
|
||||
|
||||
const params = new URLSearchParams({
|
||||
page: currentPage,
|
||||
per_page: currentPerPage,
|
||||
search: currentSearch,
|
||||
status: currentStatusFilter,
|
||||
customer: currentCustomerFilter
|
||||
});
|
||||
|
||||
fetch(`/daily_mirror/api/tune/delivery_data?${params}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
|
||||
if (data.success) {
|
||||
if (data.data.length === 0) {
|
||||
document.getElementById('noDataMessage').style.display = 'block';
|
||||
} else {
|
||||
displayDeliveryData(data.data);
|
||||
updatePagination(data);
|
||||
updateRecordsInfo(data);
|
||||
|
||||
// Populate filter dropdowns on first load
|
||||
if (currentPage === 1) {
|
||||
populateCustomerFilter(data.customers);
|
||||
populateStatusFilter(data.statuses);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error('Error loading data:', data.error);
|
||||
alert('Error loading delivery data: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
console.error('Error:', error);
|
||||
alert('Error loading delivery data: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function displayDeliveryData(data) {
|
||||
const tbody = document.getElementById('deliveryTableBody');
|
||||
tbody.innerHTML = '';
|
||||
tbody.style.display = 'table-row-group';
|
||||
|
||||
data.forEach(record => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td><strong>${record.shipment_id}</strong></td>
|
||||
<td>
|
||||
<small class="text-muted d-block">${record.customer_code}</small>
|
||||
${record.customer_name}
|
||||
</td>
|
||||
<td>${record.order_id || '-'}</td>
|
||||
<td><code>${record.article_code}</code></td>
|
||||
<td><small>${record.article_description || '-'}</small></td>
|
||||
<td><span class="badge bg-info">${record.quantity_delivered}</span></td>
|
||||
<td>${record.shipment_date || '-'}</td>
|
||||
<td>${record.delivery_date || '-'}</td>
|
||||
<td><span class="badge bg-success">${record.delivery_status}</span></td>
|
||||
<td><strong>€${parseFloat(record.total_value || 0).toFixed(2)}</strong></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" onclick="editRecord(${record.id})"
|
||||
title="Edit Delivery">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
function populateCustomerFilter(customers) {
|
||||
const filter = document.getElementById('customerFilter');
|
||||
const currentValue = filter.value;
|
||||
filter.innerHTML = '<option value="">All Customers</option>';
|
||||
|
||||
customers.forEach(customer => {
|
||||
const option = document.createElement('option');
|
||||
option.value = customer.code;
|
||||
option.textContent = `${customer.code} - ${customer.name}`;
|
||||
filter.appendChild(option);
|
||||
});
|
||||
|
||||
filter.value = currentValue;
|
||||
}
|
||||
|
||||
function populateStatusFilter(statuses) {
|
||||
const filter = document.getElementById('statusFilter');
|
||||
const currentValue = filter.value;
|
||||
filter.innerHTML = '<option value="">All Statuses</option>';
|
||||
|
||||
statuses.forEach(status => {
|
||||
const option = document.createElement('option');
|
||||
option.value = status;
|
||||
option.textContent = status;
|
||||
filter.appendChild(option);
|
||||
});
|
||||
|
||||
filter.value = currentValue;
|
||||
}
|
||||
|
||||
function updatePagination(data) {
|
||||
const pagination = document.getElementById('pagination');
|
||||
pagination.innerHTML = '';
|
||||
|
||||
if (data.total_pages <= 1) return;
|
||||
|
||||
// Previous button
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = `page-item ${data.page === 1 ? 'disabled' : ''}`;
|
||||
prevLi.innerHTML = `<a class="page-link" href="#" onclick="loadDeliveryData(${data.page - 1})">Previous</a>`;
|
||||
pagination.appendChild(prevLi);
|
||||
|
||||
// Page numbers
|
||||
const startPage = Math.max(1, data.page - 2);
|
||||
const endPage = Math.min(data.total_pages, data.page + 2);
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.className = `page-item ${i === data.page ? 'active' : ''}`;
|
||||
li.innerHTML = `<a class="page-link" href="#" onclick="loadDeliveryData(${i})">${i}</a>`;
|
||||
pagination.appendChild(li);
|
||||
}
|
||||
|
||||
// Next button
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = `page-item ${data.page === data.total_pages ? 'disabled' : ''}`;
|
||||
nextLi.innerHTML = `<a class="page-link" href="#" onclick="loadDeliveryData(${data.page + 1})">Next</a>`;
|
||||
pagination.appendChild(nextLi);
|
||||
}
|
||||
|
||||
function updateRecordsInfo(data) {
|
||||
const start = (data.page - 1) * data.per_page + 1;
|
||||
const end = Math.min(data.page * data.per_page, data.total_records);
|
||||
document.getElementById('recordsInfo').textContent =
|
||||
`Showing ${start}-${end} of ${data.total_records} deliveries`;
|
||||
}
|
||||
|
||||
function clearFilters() {
|
||||
document.getElementById('searchInput').value = '';
|
||||
document.getElementById('statusFilter').value = '';
|
||||
document.getElementById('customerFilter').value = '';
|
||||
loadDeliveryData(1);
|
||||
}
|
||||
|
||||
function editRecord(recordId) {
|
||||
// Get data via API for editing
|
||||
fetch(`/daily_mirror/api/tune/delivery_data?page=${currentPage}&per_page=${currentPerPage}&search=${currentSearch}&status=${currentStatusFilter}&customer=${currentCustomerFilter}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const recordData = data.data.find(record => record.id === recordId);
|
||||
if (recordData) {
|
||||
populateEditModal(recordData);
|
||||
const editModal = new bootstrap.Modal(document.getElementById('editModal'));
|
||||
editModal.show();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error loading record data: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function populateEditModal(record) {
|
||||
document.getElementById('editRecordId').value = record.id;
|
||||
document.getElementById('editShipmentId').value = record.shipment_id;
|
||||
document.getElementById('editOrderId').value = record.order_id || '';
|
||||
document.getElementById('editCustomerCode').value = record.customer_code;
|
||||
document.getElementById('editCustomerName').value = record.customer_name;
|
||||
document.getElementById('editArticleCode').value = record.article_code;
|
||||
document.getElementById('editDescription').value = record.article_description || '';
|
||||
document.getElementById('editQuantity').value = record.quantity_delivered;
|
||||
document.getElementById('editShipmentDate').value = record.shipment_date;
|
||||
document.getElementById('editDeliveryDate').value = record.delivery_date;
|
||||
document.getElementById('editDeliveryStatus').value = record.delivery_status;
|
||||
document.getElementById('editTotalValue').value = record.total_value;
|
||||
}
|
||||
|
||||
function saveRecord() {
|
||||
const recordId = document.getElementById('editRecordId').value;
|
||||
const data = {
|
||||
customer_code: document.getElementById('editCustomerCode').value,
|
||||
customer_name: document.getElementById('editCustomerName').value,
|
||||
order_id: document.getElementById('editOrderId').value,
|
||||
article_code: document.getElementById('editArticleCode').value,
|
||||
article_description: document.getElementById('editDescription').value,
|
||||
quantity_delivered: parseInt(document.getElementById('editQuantity').value) || 0,
|
||||
shipment_date: document.getElementById('editShipmentDate').value,
|
||||
delivery_date: document.getElementById('editDeliveryDate').value,
|
||||
delivery_status: document.getElementById('editDeliveryStatus').value,
|
||||
total_value: parseFloat(document.getElementById('editTotalValue').value) || 0
|
||||
};
|
||||
|
||||
fetch(`/daily_mirror/api/tune/delivery_data/${recordId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
// Close modal
|
||||
const editModal = bootstrap.Modal.getInstance(document.getElementById('editModal'));
|
||||
editModal.hide();
|
||||
|
||||
// Reload data
|
||||
loadDeliveryData(currentPage);
|
||||
|
||||
// Show success message
|
||||
alert('Delivery record updated successfully!');
|
||||
} else {
|
||||
alert('Error updating delivery record: ' + result.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error updating delivery record: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function saveAllChanges() {
|
||||
alert('Save All Changes functionality will be implemented for bulk operations.');
|
||||
}
|
||||
|
||||
function clearAllDelivery() {
|
||||
if (!confirm('⚠️ WARNING: This will permanently delete ALL delivery records from the database!\n\nAre you absolutely sure you want to continue?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Second confirmation for safety
|
||||
if (!confirm('This action CANNOT be undone! All delivery data will be lost.\n\nClick OK to proceed with deletion.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clearBtn = document.getElementById('clearAllBtn');
|
||||
const originalText = clearBtn.innerHTML;
|
||||
clearBtn.disabled = true;
|
||||
clearBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Deleting...';
|
||||
|
||||
fetch('/daily_mirror/clear_delivery', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('✅ ' + data.message);
|
||||
// Reload the page to show empty table
|
||||
loadDeliveryData(1);
|
||||
} else {
|
||||
alert('❌ Error: ' + (data.message || 'Failed to clear delivery records'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('❌ Error clearing delivery records: ' + error.message);
|
||||
})
|
||||
.finally(() => {
|
||||
clearBtn.disabled = false;
|
||||
clearBtn.innerHTML = originalText;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,753 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Tune Orders Data - Daily Mirror{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/daily_mirror_tune.css') }}">
|
||||
<style>
|
||||
/* Force modal width - using viewport width for maximum responsiveness */
|
||||
.modal#editModal .modal-dialog {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
margin: 1.75rem auto !important;
|
||||
}
|
||||
|
||||
.modal#editModal .modal-dialog.modal-xl {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
}
|
||||
|
||||
/* Override ALL Bootstrap media queries */
|
||||
@media (min-width: 576px) {
|
||||
.modal#editModal .modal-dialog {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.modal#editModal .modal-dialog {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.modal#editModal .modal-dialog,
|
||||
.modal#editModal .modal-dialog.modal-xl {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure pointer events work */
|
||||
.modal#editModal .modal-dialog {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- Page Header -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h3 mb-0">🛒 Tune Orders Data</h1>
|
||||
<p class="text-muted">Edit and update customer orders information</p>
|
||||
</div>
|
||||
<div>
|
||||
<!-- Buttons removed; now present in top header -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters Section -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-filter"></i> Filters and Search
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="searchInput" class="form-label">Search</label>
|
||||
<input type="text" class="form-control" id="searchInput"
|
||||
placeholder="Search by order, customer, or article...">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="statusFilter" class="form-label">Order Status</label>
|
||||
<select class="form-control" id="statusFilter">
|
||||
<option value="">All Statuses</option>
|
||||
<!-- Will be populated dynamically -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="customerFilter" class="form-label">Customer</label>
|
||||
<select class="form-control" id="customerFilter">
|
||||
<option value="">All Customers</option>
|
||||
<!-- Will be populated dynamically -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="recordsPerPage" class="form-label">Records per page</label>
|
||||
<select class="form-control" id="recordsPerPage">
|
||||
<option value="25">25</option>
|
||||
<option value="50" selected>50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button class="btn btn-primary" onclick="loadOrdersData()">
|
||||
<i class="fas fa-search"></i> Apply Filters
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="clearFilters()">
|
||||
<i class="fas fa-times"></i> Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Table Section -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-table"></i> Customer Orders Data
|
||||
</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<span id="recordsInfo" class="text-muted me-3"></span>
|
||||
{% if session.get('role') == 'superadmin' %}
|
||||
<button class="btn btn-danger btn-sm me-2" onclick="clearAllOrders()" id="clearAllBtn">
|
||||
<i class="fas fa-trash-alt"></i> Clear All Orders
|
||||
</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-success btn-sm" onclick="saveAllChanges()">
|
||||
<i class="fas fa-save"></i> Save All Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="ordersTable">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Order Line</th>
|
||||
<th>Customer</th>
|
||||
<th>Client Order Line</th>
|
||||
<th>Article Code</th>
|
||||
<th>Description</th>
|
||||
<th>Quantity</th>
|
||||
<th>Delivery Date</th>
|
||||
<th>Status</th>
|
||||
<th>Priority</th>
|
||||
<th>Product Group</th>
|
||||
<th>Order Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ordersTableBody">
|
||||
<!-- Data will be loaded here -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Loading indicator -->
|
||||
<div id="loadingIndicator" class="text-center py-4" style="display: none;">
|
||||
<i class="fas fa-spinner fa-spin fa-2x"></i>
|
||||
<p class="mt-2">Loading data...</p>
|
||||
</div>
|
||||
|
||||
<!-- No data message -->
|
||||
<div id="noDataMessage" class="text-center py-4" style="display: none;">
|
||||
<i class="fas fa-info-circle fa-2x text-muted"></i>
|
||||
<p class="mt-2 text-muted">No orders found</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="card-footer">
|
||||
<nav aria-label="Orders data pagination">
|
||||
<ul class="pagination pagination-sm justify-content-center mb-0" id="pagination">
|
||||
<!-- Pagination will be generated here -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit Modal -->
|
||||
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true" data-bs-backdrop="true" data-bs-keyboard="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable" style="max-width: 95vw !important; width: 95vw !important;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editModalLabel">Edit Customer Order</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editForm">
|
||||
<input type="hidden" id="editRecordId">
|
||||
|
||||
<div class="row">
|
||||
<!-- Column 1: Order Information -->
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editOrderLine" class="form-label">Order Line</label>
|
||||
<input type="text" class="form-control" id="editOrderLine" readonly>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editOrderId" class="form-label">Order ID</label>
|
||||
<input type="text" class="form-control" id="editOrderId">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editLineNumber" class="form-label">Line Number</label>
|
||||
<input type="text" class="form-control" id="editLineNumber">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editClientOrderLine" class="form-label">Client Order Line</label>
|
||||
<input type="text" class="form-control" id="editClientOrderLine" readonly>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editOrderDate" class="form-label">Order Date</label>
|
||||
<input type="date" class="form-control" id="editOrderDate">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editDeliveryDate" class="form-label">Delivery Date</label>
|
||||
<input type="date" class="form-control" id="editDeliveryDate">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editOrderStatus" class="form-label">Order Status</label>
|
||||
<select class="form-control" id="editOrderStatus">
|
||||
<option value="PENDING">Pending</option>
|
||||
<option value="CONFIRMED">Confirmed</option>
|
||||
<option value="Confirmat">Confirmat</option>
|
||||
<option value="IN_PROGRESS">In Progress</option>
|
||||
<option value="FINISHED">Finished</option>
|
||||
<option value="DELIVERED">Delivered</option>
|
||||
<option value="CANCELLED">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editPriority" class="form-label">Priority</label>
|
||||
<select class="form-control" id="editPriority">
|
||||
<option value="LOW">Low</option>
|
||||
<option value="NORMAL">Normal</option>
|
||||
<option value="HIGH">High</option>
|
||||
<option value="URGENT">Urgent</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 2: Customer and Article Information -->
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editCustomerCode" class="form-label">Customer Code</label>
|
||||
<input type="text" class="form-control" id="editCustomerCode">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editCustomerName" class="form-label">Customer Name</label>
|
||||
<input type="text" class="form-control" id="editCustomerName">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editArticleCode" class="form-label">Article Code</label>
|
||||
<input type="text" class="form-control" id="editArticleCode">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editDescription" class="form-label">Article Description</label>
|
||||
<textarea class="form-control" id="editDescription" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editQuantity" class="form-label">Quantity Requested</label>
|
||||
<input type="number" class="form-control" id="editQuantity">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editBalance" class="form-label">Balance</label>
|
||||
<input type="number" step="0.01" class="form-control" id="editBalance">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editUnitOfMeasure" class="form-label">Unit of Measure</label>
|
||||
<input type="text" class="form-control" id="editUnitOfMeasure">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editArticleStatus" class="form-label">Article Status</label>
|
||||
<input type="text" class="form-control" id="editArticleStatus">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 3: Production Information -->
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editProductGroup" class="form-label">Product Group</label>
|
||||
<input type="text" class="form-control" id="editProductGroup">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editModel" class="form-label">Model</label>
|
||||
<input type="text" class="form-control" id="editModel">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editProductionOrder" class="form-label">Production Order</label>
|
||||
<input type="text" class="form-control" id="editProductionOrder">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editProductionStatus" class="form-label">Production Status</label>
|
||||
<input type="text" class="form-control" id="editProductionStatus">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="editClosed" class="form-label">Closed</label>
|
||||
<input type="text" class="form-control" id="editClosed">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-danger" onclick="deleteRecord()" style="min-width: 150px;">
|
||||
<i class="fas fa-trash"></i> Delete Record
|
||||
</button>
|
||||
<div>
|
||||
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal" style="min-width: 100px;">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveRecord()" style="min-width: 150px;">
|
||||
<i class="fas fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentPage = 1;
|
||||
let currentPerPage = 50;
|
||||
let currentSearch = '';
|
||||
let currentStatusFilter = '';
|
||||
let currentCustomerFilter = '';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize theme
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
|
||||
// Load initial data
|
||||
loadOrdersData();
|
||||
|
||||
// Setup search on enter key
|
||||
document.getElementById('searchInput').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
loadOrdersData();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function loadOrdersData(page = 1) {
|
||||
currentPage = page;
|
||||
currentPerPage = document.getElementById('recordsPerPage').value;
|
||||
currentSearch = document.getElementById('searchInput').value;
|
||||
currentStatusFilter = document.getElementById('statusFilter').value;
|
||||
currentCustomerFilter = document.getElementById('customerFilter').value;
|
||||
|
||||
// Show loading indicator
|
||||
document.getElementById('loadingIndicator').style.display = 'block';
|
||||
document.getElementById('ordersTableBody').style.display = 'none';
|
||||
document.getElementById('noDataMessage').style.display = 'none';
|
||||
|
||||
const params = new URLSearchParams({
|
||||
page: currentPage,
|
||||
per_page: currentPerPage,
|
||||
search: currentSearch,
|
||||
status: currentStatusFilter,
|
||||
customer: currentCustomerFilter
|
||||
});
|
||||
|
||||
fetch(`/daily_mirror/api/tune/orders_data?${params}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
|
||||
if (data.success) {
|
||||
if (data.data.length === 0) {
|
||||
document.getElementById('noDataMessage').style.display = 'block';
|
||||
} else {
|
||||
displayOrdersData(data.data);
|
||||
updatePagination(data);
|
||||
updateRecordsInfo(data);
|
||||
|
||||
// Populate filter dropdowns on first load
|
||||
if (currentPage === 1) {
|
||||
populateCustomerFilter(data.customers);
|
||||
populateStatusFilter(data.statuses);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error('Error loading data:', data.error);
|
||||
alert('Error loading orders data: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById('loadingIndicator').style.display = 'none';
|
||||
console.error('Error:', error);
|
||||
alert('Error loading orders data: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function displayOrdersData(data) {
|
||||
const tbody = document.getElementById('ordersTableBody');
|
||||
tbody.innerHTML = '';
|
||||
tbody.style.display = 'table-row-group';
|
||||
|
||||
data.forEach(record => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td><strong>${record.order_line}</strong></td>
|
||||
<td>
|
||||
<small class="text-muted d-block">${record.customer_code}</small>
|
||||
${record.customer_name}
|
||||
</td>
|
||||
<td>${record.client_order_line || '-'}</td>
|
||||
<td><code>${record.article_code}</code></td>
|
||||
<td><small>${record.article_description || '-'}</small></td>
|
||||
<td><span class="badge bg-info">${record.quantity_requested}</span></td>
|
||||
<td>${record.delivery_date || '-'}</td>
|
||||
<td><span class="badge bg-primary">${record.order_status}</span></td>
|
||||
<td><span class="badge bg-warning">${record.priority || 'NORMAL'}</span></td>
|
||||
<td><small>${record.product_group || '-'}</small></td>
|
||||
<td>${record.order_date || '-'}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" onclick="editRecord(${record.id})"
|
||||
title="Edit Order">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
function populateCustomerFilter(customers) {
|
||||
const filter = document.getElementById('customerFilter');
|
||||
// Keep the "All Customers" option and add new ones
|
||||
const currentValue = filter.value;
|
||||
filter.innerHTML = '<option value="">All Customers</option>';
|
||||
|
||||
customers.forEach(customer => {
|
||||
const option = document.createElement('option');
|
||||
option.value = customer.code;
|
||||
option.textContent = `${customer.code} - ${customer.name}`;
|
||||
filter.appendChild(option);
|
||||
});
|
||||
|
||||
filter.value = currentValue;
|
||||
}
|
||||
|
||||
function populateStatusFilter(statuses) {
|
||||
const filter = document.getElementById('statusFilter');
|
||||
const currentValue = filter.value;
|
||||
filter.innerHTML = '<option value="">All Statuses</option>';
|
||||
|
||||
statuses.forEach(status => {
|
||||
const option = document.createElement('option');
|
||||
option.value = status;
|
||||
option.textContent = status;
|
||||
filter.appendChild(option);
|
||||
});
|
||||
|
||||
filter.value = currentValue;
|
||||
}
|
||||
|
||||
function updatePagination(data) {
|
||||
const pagination = document.getElementById('pagination');
|
||||
pagination.innerHTML = '';
|
||||
|
||||
if (data.total_pages <= 1) return;
|
||||
|
||||
// Previous button
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = `page-item ${data.page === 1 ? 'disabled' : ''}`;
|
||||
prevLi.innerHTML = `<a class="page-link" href="#" onclick="loadOrdersData(${data.page - 1})">Previous</a>`;
|
||||
pagination.appendChild(prevLi);
|
||||
|
||||
// Page numbers
|
||||
const startPage = Math.max(1, data.page - 2);
|
||||
const endPage = Math.min(data.total_pages, data.page + 2);
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.className = `page-item ${i === data.page ? 'active' : ''}`;
|
||||
li.innerHTML = `<a class="page-link" href="#" onclick="loadOrdersData(${i})">${i}</a>`;
|
||||
pagination.appendChild(li);
|
||||
}
|
||||
|
||||
// Next button
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = `page-item ${data.page === data.total_pages ? 'disabled' : ''}`;
|
||||
nextLi.innerHTML = `<a class="page-link" href="#" onclick="loadOrdersData(${data.page + 1})">Next</a>`;
|
||||
pagination.appendChild(nextLi);
|
||||
}
|
||||
|
||||
function updateRecordsInfo(data) {
|
||||
const start = (data.page - 1) * data.per_page + 1;
|
||||
const end = Math.min(data.page * data.per_page, data.total_records);
|
||||
document.getElementById('recordsInfo').textContent =
|
||||
`Showing ${start}-${end} of ${data.total_records} orders`;
|
||||
}
|
||||
|
||||
function clearFilters() {
|
||||
document.getElementById('searchInput').value = '';
|
||||
document.getElementById('statusFilter').value = '';
|
||||
document.getElementById('customerFilter').value = '';
|
||||
loadOrdersData(1);
|
||||
}
|
||||
|
||||
function editRecord(recordId) {
|
||||
// Find the record data from the current display
|
||||
const rows = document.querySelectorAll('#ordersTableBody tr');
|
||||
let recordData = null;
|
||||
|
||||
// Get data via API for editing
|
||||
fetch(`/daily_mirror/api/tune/orders_data?page=${currentPage}&per_page=${currentPerPage}&search=${currentSearch}&status=${currentStatusFilter}&customer=${currentCustomerFilter}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
recordData = data.data.find(record => record.id === recordId);
|
||||
if (recordData) {
|
||||
populateEditModal(recordData);
|
||||
|
||||
// Get modal elements
|
||||
const modalElement = document.getElementById('editModal');
|
||||
const modalDialog = modalElement.querySelector('.modal-dialog');
|
||||
|
||||
// Remove any existing modal instances to prevent conflicts
|
||||
const existingModal = bootstrap.Modal.getInstance(modalElement);
|
||||
if (existingModal) {
|
||||
existingModal.dispose();
|
||||
}
|
||||
|
||||
const modal = new bootstrap.Modal(modalElement, {
|
||||
backdrop: true,
|
||||
keyboard: true,
|
||||
focus: true
|
||||
});
|
||||
|
||||
// Show the modal first
|
||||
modal.show();
|
||||
|
||||
// Force the modal dialog width AFTER modal is shown - using 95% of viewport width
|
||||
setTimeout(() => {
|
||||
if (modalDialog) {
|
||||
console.log('Applying width after modal shown');
|
||||
modalDialog.style.setProperty('max-width', '95vw', 'important');
|
||||
modalDialog.style.setProperty('width', '95vw', 'important');
|
||||
modalDialog.style.setProperty('margin', '1.75rem auto', 'important');
|
||||
|
||||
// Also apply to modal content for good measure
|
||||
const modalContent = modalDialog.querySelector('.modal-content');
|
||||
if (modalContent) {
|
||||
modalContent.style.setProperty('width', '100%', 'important');
|
||||
}
|
||||
|
||||
console.log('Modal dialog computed width:', window.getComputedStyle(modalDialog).width);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error loading record data: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function populateEditModal(record) {
|
||||
document.getElementById('editRecordId').value = record.id;
|
||||
document.getElementById('editOrderLine').value = record.order_line;
|
||||
document.getElementById('editOrderId').value = record.order_id;
|
||||
document.getElementById('editLineNumber').value = record.line_number || '';
|
||||
document.getElementById('editCustomerCode').value = record.customer_code;
|
||||
document.getElementById('editCustomerName').value = record.customer_name;
|
||||
document.getElementById('editClientOrderLine').value = record.client_order_line || '';
|
||||
document.getElementById('editArticleCode').value = record.article_code;
|
||||
document.getElementById('editDescription').value = record.article_description || '';
|
||||
document.getElementById('editQuantity').value = record.quantity_requested;
|
||||
document.getElementById('editBalance').value = record.balance || '';
|
||||
document.getElementById('editUnitOfMeasure').value = record.unit_of_measure || '';
|
||||
document.getElementById('editDeliveryDate').value = record.delivery_date;
|
||||
document.getElementById('editOrderDate').value = record.order_date;
|
||||
document.getElementById('editOrderStatus').value = record.order_status;
|
||||
document.getElementById('editArticleStatus').value = record.article_status || '';
|
||||
document.getElementById('editPriority').value = record.priority || 'NORMAL';
|
||||
document.getElementById('editProductGroup').value = record.product_group || '';
|
||||
document.getElementById('editProductionOrder').value = record.production_order || '';
|
||||
document.getElementById('editProductionStatus').value = record.production_status || '';
|
||||
document.getElementById('editModel').value = record.model || '';
|
||||
document.getElementById('editClosed').value = record.closed || '';
|
||||
}
|
||||
|
||||
function saveRecord() {
|
||||
const recordId = document.getElementById('editRecordId').value;
|
||||
const data = {
|
||||
order_line: document.getElementById('editOrderLine').value,
|
||||
order_id: document.getElementById('editOrderId').value,
|
||||
line_number: document.getElementById('editLineNumber').value,
|
||||
customer_code: document.getElementById('editCustomerCode').value,
|
||||
customer_name: document.getElementById('editCustomerName').value,
|
||||
client_order_line: document.getElementById('editClientOrderLine').value,
|
||||
article_code: document.getElementById('editArticleCode').value,
|
||||
article_description: document.getElementById('editDescription').value,
|
||||
quantity_requested: parseInt(document.getElementById('editQuantity').value) || 0,
|
||||
balance: parseFloat(document.getElementById('editBalance').value) || null,
|
||||
unit_of_measure: document.getElementById('editUnitOfMeasure').value,
|
||||
delivery_date: document.getElementById('editDeliveryDate').value,
|
||||
order_date: document.getElementById('editOrderDate').value,
|
||||
order_status: document.getElementById('editOrderStatus').value,
|
||||
article_status: document.getElementById('editArticleStatus').value,
|
||||
priority: document.getElementById('editPriority').value,
|
||||
product_group: document.getElementById('editProductGroup').value,
|
||||
production_order: document.getElementById('editProductionOrder').value,
|
||||
production_status: document.getElementById('editProductionStatus').value,
|
||||
model: document.getElementById('editModel').value,
|
||||
closed: document.getElementById('editClosed').value
|
||||
};
|
||||
|
||||
fetch(`/daily_mirror/api/tune/orders_data/${recordId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
// Close modal
|
||||
const editModal = bootstrap.Modal.getInstance(document.getElementById('editModal'));
|
||||
editModal.hide();
|
||||
|
||||
// Reload data
|
||||
loadOrdersData(currentPage);
|
||||
|
||||
// Show success message
|
||||
alert('Order updated successfully!');
|
||||
} else {
|
||||
alert('Error updating order: ' + result.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error updating order: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteRecord() {
|
||||
const recordId = document.getElementById('editRecordId').value;
|
||||
const orderLine = document.getElementById('editOrderLine').value;
|
||||
|
||||
if (!confirm(`⚠️ Are you sure you want to delete order line "${orderLine}"?\n\nThis action cannot be undone.`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/daily_mirror/api/tune/orders_data/${recordId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
// Close modal and reload data
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('editModal'));
|
||||
modal.hide();
|
||||
|
||||
alert('Record deleted successfully!');
|
||||
loadOrdersData(currentPage);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error deleting record:', error);
|
||||
alert('Error deleting record: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function saveAllChanges() {
|
||||
alert('Save All Changes functionality will be implemented for bulk operations.');
|
||||
}
|
||||
|
||||
function clearAllOrders() {
|
||||
if (!confirm('⚠️ WARNING: This will permanently delete ALL customer orders from the database!\n\nAre you absolutely sure you want to continue?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Second confirmation for safety
|
||||
if (!confirm('This action CANNOT be undone! All customer order data will be lost.\n\nClick OK to proceed with deletion.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clearBtn = document.getElementById('clearAllBtn');
|
||||
const originalText = clearBtn.innerHTML;
|
||||
clearBtn.disabled = true;
|
||||
clearBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Deleting...';
|
||||
|
||||
fetch('/daily_mirror/clear_orders', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('✅ ' + data.message);
|
||||
// Reload the page to show empty table
|
||||
loadOrdersData(1);
|
||||
} else {
|
||||
alert('❌ Error: ' + (data.message || 'Failed to clear orders'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('❌ Error clearing orders: ' + error.message);
|
||||
})
|
||||
.finally(() => {
|
||||
clearBtn.disabled = false;
|
||||
clearBtn.innerHTML = originalText;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||