From af62fa478fc052c25f499e9333183bb5dd4a046f Mon Sep 17 00:00:00 2001 From: Quality System Admin Date: Sat, 11 Oct 2025 21:45:37 +0300 Subject: [PATCH] feat: Implement comprehensive database setup system - Add complete database setup script (setup_complete_database.py) - Add quick deployment script (quick_deploy.sh) - Add comprehensive documentation (DATABASE_SETUP_README.md) - Move individual db scripts to backup_db_scripts folder - Update external_server.conf with correct database settings - Clean up obsolete documentation files - Streamline deployment process to single command Features: - One-script database creation for all tables and triggers - Automated permissions and roles setup - Complete verification and error handling - Production-ready deployment workflow - Maintains backward compatibility with individual scripts --- py_app/DATABASE_SETUP_README.md | 133 ++++ py_app/ENHANCED_PRINT_CONTROLLER.md | 263 -------- py_app/MOBILE_LOGIN_GUIDE.md | 133 ---- py_app/PRINT_PROGRESS_FEATURE.md | 125 ---- .../add_email_column.py | 0 .../check_external_db_users.py | 0 .../create_external_superadmin.py | 0 .../create_order_for_labels_table.py | 0 .../create_permissions_tables.py | 0 .../create_roles_table.py | 0 .../create_scan_1db.py | 2 +- .../create_scanfg_orders.py | 2 +- .../create_triggers.py | 2 +- .../create_triggers_fg.py | 2 +- .../create_warehouse_locations_table.py | 0 .../delet scan1_orders values.py | 0 .../drop_external_users_roles_tables.py | 0 .../find_users_databases.py | 0 .../populate_permissions.py | 0 .../print_internal_users.py | 0 .../query.py | 0 .../recreate_order_for_labels_table.py | 0 .../seed_internal_superadmin.py | 0 .../test.py | 0 .../add_printed_labels_column.py | 151 ----- .../setup_complete_database.py | 637 ++++++++++++++++++ py_app/instance/external_server.conf | 4 +- py_app/instance/users.db | Bin 32768 -> 24576 bytes py_app/quick_deploy.sh | 142 ++++ to_do_install.txt | 7 +- 30 files changed, 924 insertions(+), 679 deletions(-) create mode 100644 py_app/DATABASE_SETUP_README.md delete mode 100755 py_app/ENHANCED_PRINT_CONTROLLER.md delete mode 100644 py_app/MOBILE_LOGIN_GUIDE.md delete mode 100755 py_app/PRINT_PROGRESS_FEATURE.md rename py_app/app/{db_create_scripts => backup_db_scripts}/add_email_column.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/check_external_db_users.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_external_superadmin.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_order_for_labels_table.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_permissions_tables.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_roles_table.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_scan_1db.py (97%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_scanfg_orders.py (96%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_triggers.py (98%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_triggers_fg.py (98%) rename py_app/app/{db_create_scripts => backup_db_scripts}/create_warehouse_locations_table.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/delet scan1_orders values.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/drop_external_users_roles_tables.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/find_users_databases.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/populate_permissions.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/print_internal_users.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/query.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/recreate_order_for_labels_table.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/seed_internal_superadmin.py (100%) rename py_app/app/{db_create_scripts => backup_db_scripts}/test.py (100%) delete mode 100755 py_app/app/db_create_scripts/add_printed_labels_column.py create mode 100755 py_app/app/db_create_scripts/setup_complete_database.py mode change 100755 => 100644 py_app/instance/users.db create mode 100755 py_app/quick_deploy.sh diff --git a/py_app/DATABASE_SETUP_README.md b/py_app/DATABASE_SETUP_README.md new file mode 100644 index 0000000..73c617b --- /dev/null +++ b/py_app/DATABASE_SETUP_README.md @@ -0,0 +1,133 @@ +# 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. \ No newline at end of file diff --git a/py_app/ENHANCED_PRINT_CONTROLLER.md b/py_app/ENHANCED_PRINT_CONTROLLER.md deleted file mode 100755 index 8ab36b9..0000000 --- a/py_app/ENHANCED_PRINT_CONTROLLER.md +++ /dev/null @@ -1,263 +0,0 @@ -# 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 diff --git a/py_app/MOBILE_LOGIN_GUIDE.md b/py_app/MOBILE_LOGIN_GUIDE.md deleted file mode 100644 index 4cf9d32..0000000 --- a/py_app/MOBILE_LOGIN_GUIDE.md +++ /dev/null @@ -1,133 +0,0 @@ -# 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** \ No newline at end of file diff --git a/py_app/PRINT_PROGRESS_FEATURE.md b/py_app/PRINT_PROGRESS_FEATURE.md deleted file mode 100755 index 246a1c6..0000000 --- a/py_app/PRINT_PROGRESS_FEATURE.md +++ /dev/null @@ -1,125 +0,0 @@ -# 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/` 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/` -- **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 diff --git a/py_app/app/db_create_scripts/add_email_column.py b/py_app/app/backup_db_scripts/add_email_column.py similarity index 100% rename from py_app/app/db_create_scripts/add_email_column.py rename to py_app/app/backup_db_scripts/add_email_column.py diff --git a/py_app/app/db_create_scripts/check_external_db_users.py b/py_app/app/backup_db_scripts/check_external_db_users.py similarity index 100% rename from py_app/app/db_create_scripts/check_external_db_users.py rename to py_app/app/backup_db_scripts/check_external_db_users.py diff --git a/py_app/app/db_create_scripts/create_external_superadmin.py b/py_app/app/backup_db_scripts/create_external_superadmin.py similarity index 100% rename from py_app/app/db_create_scripts/create_external_superadmin.py rename to py_app/app/backup_db_scripts/create_external_superadmin.py diff --git a/py_app/app/db_create_scripts/create_order_for_labels_table.py b/py_app/app/backup_db_scripts/create_order_for_labels_table.py similarity index 100% rename from py_app/app/db_create_scripts/create_order_for_labels_table.py rename to py_app/app/backup_db_scripts/create_order_for_labels_table.py diff --git a/py_app/app/db_create_scripts/create_permissions_tables.py b/py_app/app/backup_db_scripts/create_permissions_tables.py similarity index 100% rename from py_app/app/db_create_scripts/create_permissions_tables.py rename to py_app/app/backup_db_scripts/create_permissions_tables.py diff --git a/py_app/app/db_create_scripts/create_roles_table.py b/py_app/app/backup_db_scripts/create_roles_table.py similarity index 100% rename from py_app/app/db_create_scripts/create_roles_table.py rename to py_app/app/backup_db_scripts/create_roles_table.py diff --git a/py_app/app/db_create_scripts/create_scan_1db.py b/py_app/app/backup_db_scripts/create_scan_1db.py similarity index 97% rename from py_app/app/db_create_scripts/create_scan_1db.py rename to py_app/app/backup_db_scripts/create_scan_1db.py index 95cc274..5f76e3f 100755 --- a/py_app/app/db_create_scripts/create_scan_1db.py +++ b/py_app/app/backup_db_scripts/create_scan_1db.py @@ -5,7 +5,7 @@ db_config = { "user": "trasabilitate", "password": "Initial01!", "host": "localhost", - "database": "trasabilitate_database" + "database": "trasabilitate" } # Connect to the database diff --git a/py_app/app/db_create_scripts/create_scanfg_orders.py b/py_app/app/backup_db_scripts/create_scanfg_orders.py similarity index 96% rename from py_app/app/db_create_scripts/create_scanfg_orders.py rename to py_app/app/backup_db_scripts/create_scanfg_orders.py index 45dd5bb..f461039 100644 --- a/py_app/app/db_create_scripts/create_scanfg_orders.py +++ b/py_app/app/backup_db_scripts/create_scanfg_orders.py @@ -6,7 +6,7 @@ db_config = { "user": "trasabilitate", "password": "Initial01!", "host": "localhost", - "database": "trasabilitate_database" + "database": "trasabilitate" } try: diff --git a/py_app/app/db_create_scripts/create_triggers.py b/py_app/app/backup_db_scripts/create_triggers.py similarity index 98% rename from py_app/app/db_create_scripts/create_triggers.py rename to py_app/app/backup_db_scripts/create_triggers.py index d1edb1e..c7a04ed 100755 --- a/py_app/app/db_create_scripts/create_triggers.py +++ b/py_app/app/backup_db_scripts/create_triggers.py @@ -5,7 +5,7 @@ db_config = { "user": "trasabilitate", "password": "Initial01!", "host": "localhost", - "database": "trasabilitate_database" + "database": "trasabilitate" } # Connect to the database diff --git a/py_app/app/db_create_scripts/create_triggers_fg.py b/py_app/app/backup_db_scripts/create_triggers_fg.py similarity index 98% rename from py_app/app/db_create_scripts/create_triggers_fg.py rename to py_app/app/backup_db_scripts/create_triggers_fg.py index 17a5ba0..3246f06 100644 --- a/py_app/app/db_create_scripts/create_triggers_fg.py +++ b/py_app/app/backup_db_scripts/create_triggers_fg.py @@ -5,7 +5,7 @@ db_config = { "user": "trasabilitate", "password": "Initial01!", "host": "localhost", - "database": "trasabilitate_database" + "database": "trasabilitate" } # Connect to the database diff --git a/py_app/app/db_create_scripts/create_warehouse_locations_table.py b/py_app/app/backup_db_scripts/create_warehouse_locations_table.py similarity index 100% rename from py_app/app/db_create_scripts/create_warehouse_locations_table.py rename to py_app/app/backup_db_scripts/create_warehouse_locations_table.py diff --git a/py_app/app/db_create_scripts/delet scan1_orders values.py b/py_app/app/backup_db_scripts/delet scan1_orders values.py similarity index 100% rename from py_app/app/db_create_scripts/delet scan1_orders values.py rename to py_app/app/backup_db_scripts/delet scan1_orders values.py diff --git a/py_app/app/db_create_scripts/drop_external_users_roles_tables.py b/py_app/app/backup_db_scripts/drop_external_users_roles_tables.py similarity index 100% rename from py_app/app/db_create_scripts/drop_external_users_roles_tables.py rename to py_app/app/backup_db_scripts/drop_external_users_roles_tables.py diff --git a/py_app/app/db_create_scripts/find_users_databases.py b/py_app/app/backup_db_scripts/find_users_databases.py similarity index 100% rename from py_app/app/db_create_scripts/find_users_databases.py rename to py_app/app/backup_db_scripts/find_users_databases.py diff --git a/py_app/app/db_create_scripts/populate_permissions.py b/py_app/app/backup_db_scripts/populate_permissions.py similarity index 100% rename from py_app/app/db_create_scripts/populate_permissions.py rename to py_app/app/backup_db_scripts/populate_permissions.py diff --git a/py_app/app/db_create_scripts/print_internal_users.py b/py_app/app/backup_db_scripts/print_internal_users.py similarity index 100% rename from py_app/app/db_create_scripts/print_internal_users.py rename to py_app/app/backup_db_scripts/print_internal_users.py diff --git a/py_app/app/db_create_scripts/query.py b/py_app/app/backup_db_scripts/query.py similarity index 100% rename from py_app/app/db_create_scripts/query.py rename to py_app/app/backup_db_scripts/query.py diff --git a/py_app/app/db_create_scripts/recreate_order_for_labels_table.py b/py_app/app/backup_db_scripts/recreate_order_for_labels_table.py similarity index 100% rename from py_app/app/db_create_scripts/recreate_order_for_labels_table.py rename to py_app/app/backup_db_scripts/recreate_order_for_labels_table.py diff --git a/py_app/app/db_create_scripts/seed_internal_superadmin.py b/py_app/app/backup_db_scripts/seed_internal_superadmin.py similarity index 100% rename from py_app/app/db_create_scripts/seed_internal_superadmin.py rename to py_app/app/backup_db_scripts/seed_internal_superadmin.py diff --git a/py_app/app/db_create_scripts/test.py b/py_app/app/backup_db_scripts/test.py similarity index 100% rename from py_app/app/db_create_scripts/test.py rename to py_app/app/backup_db_scripts/test.py diff --git a/py_app/app/db_create_scripts/add_printed_labels_column.py b/py_app/app/db_create_scripts/add_printed_labels_column.py deleted file mode 100755 index fe04ec4..0000000 --- a/py_app/app/db_create_scripts/add_printed_labels_column.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/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) \ No newline at end of file diff --git a/py_app/app/db_create_scripts/setup_complete_database.py b/py_app/app/db_create_scripts/setup_complete_database.py new file mode 100755 index 0000000..f1d81e2 --- /dev/null +++ b/py_app/app/db_create_scripts/setup_complete_database.py @@ -0,0 +1,637 @@ +#!/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 +""" + +import mariadb +import sqlite3 +import os +import sys +from datetime import datetime + +# Database configuration +DB_CONFIG = { + "user": "trasabilitate", + "password": "Initial01!", + "host": "localhost", + "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}") + +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""" + 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 + ); + """ + 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_sqlite_tables(): + """Create SQLite tables for users and roles""" + print_step(6, "Creating SQLite User and Role Tables") + + 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(7, "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(8, "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(9, "Updating External Server Configuration") + + try: + config_path = os.path.join(os.path.dirname(__file__), '../../instance/external_server.conf') + + config_content = """server_domain=localhost +port=3306 +database_name=trasabilitate +username=trasabilitate +password=Initial01! +""" + + # 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("External server configuration updated") + 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(10, "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' + ] + + 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_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() \ No newline at end of file diff --git a/py_app/instance/external_server.conf b/py_app/instance/external_server.conf index 271cc7b..7644f16 100755 --- a/py_app/instance/external_server.conf +++ b/py_app/instance/external_server.conf @@ -1,5 +1,5 @@ server_domain=localhost -port=3602 -database_name=trasabilitate_database +port=3306 +database_name=trasabilitate username=trasabilitate password=Initial01! diff --git a/py_app/instance/users.db b/py_app/instance/users.db old mode 100755 new mode 100644 index 2fbee98c07234fe6301c7e843e5d1e6129c30539..ffd3ecb124c37b0f0078e48a7b1ae0ee7111c287 GIT binary patch delta 204 zcmZo@U}`wPI6+#FiGhKE4TxcYX`+s?I1__jRUt3`4+d7=Dh9rX{Ac<4d8_zRHVX={ z@JcnNv#^Vci!(OsmLw+Sq!#7pq!xn-*2#Bx6es`WF`KN-t35f0S7&k+uPnO)5NK+$ zPCm~s!vj_pZwRI)Z{rK$%w&WZWjI-wUw86X9;?Y&{MwUy`86i5<(FpxY2AE+-%f$; i4Fmr-{x_Qi6&~+|bYd60D delta 474 zcmZoTz}V2hG(lRBg@J*A1BhXOd7_T7Gz)`XStl?54+eIgLk#?!{Ac;L^B(5w<2l4T zV`HNSk5pqY8@sr;IAb$wNn%n?YEgbpYB88#pFD+Eaq>=Hqsi}i)hA2wX-szGlVsM^ zWS@MVU#1?cB;F8AaWs0cu#1a|GBy>1%_uESEdpUy=O91{Y^$ zih`$Kh^xD6kb<9oh=O0JkB^Q57bi$MFEKY&A_O3T&?#_`mYM-YlqapMUZjdoDpvMrLtFkU7Onyr7s807^aNpEyC1 LjSGdl$Uy-BhX{oG diff --git a/py_app/quick_deploy.sh b/py_app/quick_deploy.sh new file mode 100755 index 0000000..3a9f1e2 --- /dev/null +++ b/py_app/quick_deploy.sh @@ -0,0 +1,142 @@ +#!/bin/bash + +# Trasabilitate Application - Quick Deployment Script +# This script handles the complete deployment process + +set -e # Exit on any error + +echo "🚀 Trasabilitate Application - Quick Deployment" +echo "==============================================" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +print_step() { + echo -e "\n${BLUE}📋 Step $1: $2${NC}" + echo "----------------------------------------" +} + +print_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠️ $1${NC}" +} + +print_error() { + echo -e "${RED}❌ $1${NC}" +} + +# Check if running as root +if [[ $EUID -eq 0 ]]; then + print_error "This script should not be run as root for security reasons" + exit 1 +fi + +print_step 1 "Checking Prerequisites" + +# Check if we're in the right directory +if [[ ! -f "run.py" ]]; then + print_error "Please run this script from the py_app directory" + print_error "Expected location: /srv/quality_recticel/py_app" + exit 1 +fi + +print_success "Running from correct directory" + +# Check if MariaDB is running +if ! systemctl is-active --quiet mariadb; then + print_warning "MariaDB is not running. Attempting to start..." + if sudo systemctl start mariadb; then + print_success "MariaDB started successfully" + else + print_error "Failed to start MariaDB. Please start it manually:" + print_error "sudo systemctl start mariadb" + exit 1 + fi +else + print_success "MariaDB is running" +fi + +# Check if virtual environment exists +if [[ ! -d "../recticel" ]]; then + print_error "Virtual environment 'recticel' not found" + print_error "Please create it first:" + print_error "python3 -m venv ../recticel" + exit 1 +fi + +print_success "Virtual environment found" + +print_step 2 "Setting up Database and User" + +# Create database and user +print_warning "You may be prompted for the MySQL root password" +if sudo mysql -e "CREATE DATABASE IF NOT EXISTS trasabilitate; CREATE USER IF NOT EXISTS 'trasabilitate'@'localhost' IDENTIFIED BY 'Initial01!'; GRANT ALL PRIVILEGES ON trasabilitate.* TO 'trasabilitate'@'localhost'; FLUSH PRIVILEGES;" 2>/dev/null; then + print_success "Database 'trasabilitate' and user created successfully" +else + print_error "Failed to create database or user. Please check MySQL root access" + exit 1 +fi + +print_step 3 "Activating Virtual Environment and Installing Dependencies" + +# Activate virtual environment and install dependencies +source ../recticel/bin/activate + +if pip install -r requirements.txt > /dev/null 2>&1; then + print_success "Python dependencies installed/verified" +else + print_error "Failed to install Python dependencies" + exit 1 +fi + +print_step 4 "Running Complete Database Setup" + +# Run the comprehensive database setup script +if python3 app/db_create_scripts/setup_complete_database.py; then + print_success "Database setup completed successfully" +else + print_error "Database setup failed" + exit 1 +fi + +print_step 5 "Testing Application Startup" + +# Test if the application can start (run for 3 seconds then kill) +print_warning "Testing application startup (will stop after 3 seconds)..." + +timeout 3s python3 run.py > /dev/null 2>&1 || true +print_success "Application startup test completed" + +echo "" +echo "==============================================" +echo -e "${GREEN}🎉 DEPLOYMENT COMPLETED SUCCESSFULLY!${NC}" +echo "==============================================" +echo "" +echo "📋 Deployment Summary:" +echo " • MariaDB database and user configured" +echo " • All database tables and triggers created" +echo " • Permissions system initialized" +echo " • Default superadmin user ready" +echo "" +echo "🚀 To start the application:" +echo " cd /srv/quality_recticel/py_app" +echo " source ../recticel/bin/activate" +echo " python3 run.py" +echo "" +echo "🌐 Application URLs:" +echo " • Local: http://127.0.0.1:8781" +echo " • Network: http://$(hostname -I | awk '{print $1}'):8781" +echo "" +echo "👤 Default Login:" +echo " • Username: superadmin" +echo " • Password: superadmin123" +echo "" +echo -e "${YELLOW}⚠️ Remember to change the default password after first login!${NC}" +echo "" \ No newline at end of file diff --git a/to_do_install.txt b/to_do_install.txt index 22a570a..e996dc8 100644 --- a/to_do_install.txt +++ b/to_do_install.txt @@ -15,7 +15,12 @@ sudo apt install -y mariadb-server libmariadb-dev 5. Create MariaDB database and user: - sudo mysql -e "CREATE DATABASE recticel; CREATE USER 'sa'@'localhost' IDENTIFIED BY '12345678'; GRANT ALL PRIVILEGES ON recticel.* TO 'sa'@'localhost'; FLUSH PRIVILEGES;" + sudo mysql -e "CREATE DATABASE trasabilitate; CREATE USER 'sa'@'localhost' IDENTIFIED BY 'qasdewrftgbcgfdsrytkmbf\"b'; GRANT ALL PRIVILEGES ON quality.* TO 'sa'@'localhost'; FLUSH PRIVILEGES;" + sa + qasdewrftgbcgfdsrytkmbf\"b + + trasabilitate + Initial01! 6. Install build tools (for compiling Python packages): sudo apt install -y build-essential