updated control access

This commit is contained in:
Quality System Admin
2025-10-16 02:36:32 +03:00
parent 50c791e242
commit c96039542d
266 changed files with 32656 additions and 9 deletions

View File

@@ -1,361 +0,0 @@
# Quality Recticel Windows Print Service - Installation Guide
## 📋 Overview
The Quality Recticel Windows Print Service enables **silent PDF printing** directly from the web application through a Chrome extension. This system eliminates the need for manual PDF downloads and provides seamless label printing functionality.
## 🏗️ System Architecture
```
Web Application (print_module.html)
Windows Print Service (localhost:8765)
Chrome Extension (Native Messaging)
Windows Print System
```
## 📦 Package Contents
```
windows_print_service/
├── print_service.py # Main Windows service (Flask API)
├── service_manager.py # Service installation & management
├── install_service.bat # Automated installation script
├── chrome_extension/ # Chrome extension files
│ ├── manifest.json # Extension configuration
│ ├── background.js # Service worker
│ ├── content.js # Page integration
│ ├── popup.html # Extension UI
│ ├── popup.js # Extension logic
│ └── icons/ # Extension icons
└── INSTALLATION_GUIDE.md # This documentation
```
## 🔧 Prerequisites
### System Requirements
- **Operating System**: Windows 10/11 (64-bit)
- **Python**: Python 3.8 or higher
- **Browser**: Google Chrome (latest version)
- **Privileges**: Administrator access required for installation
### Python Dependencies
The following packages will be installed automatically:
- `flask` - Web service framework
- `flask-cors` - Cross-origin resource sharing
- `requests` - HTTP client library
- `pywin32` - Windows service integration
## 🚀 Installation Process
### Step 1: Download and Extract Files
1. Download the `windows_print_service` folder to your system
2. Extract to a permanent location (e.g., `C:\QualityRecticel\PrintService\`)
3. **Do not move or delete this folder after installation**
### Step 2: Install Windows Service
#### Method A: Automated Installation (Recommended)
1. **Right-click** on `install_service.bat`
2. Select **"Run as administrator"**
3. Click **"Yes"** when Windows UAC prompt appears
4. Wait for installation to complete
#### Method B: Manual Installation
If the automated script fails, follow these steps:
```bash
# Open Command Prompt as Administrator
cd C:\path\to\windows_print_service
# Install Python dependencies
pip install flask flask-cors requests pywin32
# Install Windows service
python service_manager.py install
# Add firewall exception
netsh advfirewall firewall add rule name="Quality Recticel Print Service" dir=in action=allow protocol=TCP localport=8765
# Create Chrome extension registry entry
reg add "HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.qualityrecticel.printservice" /ve /d "%cd%\chrome_extension\manifest.json" /f
```
### Step 3: Install Chrome Extension
1. Open **Google Chrome**
2. Navigate to `chrome://extensions/`
3. Enable **"Developer mode"** (toggle in top-right corner)
4. Click **"Load unpacked"**
5. Select the `chrome_extension` folder
6. Verify the extension appears with a printer icon
### Step 4: Verify Installation
#### Check Windows Service Status
1. Press `Win + R`, type `services.msc`, press Enter
2. Look for **"Quality Recticel Print Service"**
3. Status should show **"Running"**
4. Startup type should be **"Automatic"**
#### Test API Endpoints
Open a web browser and visit:
- **Health Check**: `http://localhost:8765/health`
- **Printer List**: `http://localhost:8765/printers`
Expected response for health check:
```json
{
"status": "healthy",
"service": "Quality Recticel Print Service",
"version": "1.0",
"timestamp": "2025-09-21T10:30:00"
}
```
#### Test Chrome Extension
1. Click the extension icon in Chrome toolbar
2. Verify it shows "Service Status: Connected ✅"
3. Check that printers are listed
4. Try the "Test Print" button
## 🔄 Web Application Integration
The web application automatically detects the Windows service and adapts the user interface:
### Service Available (Green Button)
- Button text: **"🖨️ Print Labels (Silent)"**
- Functionality: Direct printing to default printer
- User experience: Click → Labels print immediately
### Service Unavailable (Blue Button)
- Button text: **"📄 Generate PDF"**
- Functionality: PDF download for manual printing
- User experience: Click → PDF downloads to browser
### Detection Logic
```javascript
// Automatic service detection on page load
const response = await fetch('http://localhost:8765/health');
if (response.ok) {
// Service available - enable silent printing
} else {
// Service unavailable - fallback to PDF download
}
```
## 🛠️ Configuration
### Service Configuration
The service runs with the following default settings:
| Setting | Value | Description |
|---------|-------|-------------|
| **Port** | 8765 | Local API port |
| **Host** | localhost | Service binding |
| **Startup** | Automatic | Starts with Windows |
| **Printer** | Default | Uses system default printer |
| **Copies** | 1 | Default print copies |
### Chrome Extension Permissions
The extension requires these permissions:
- `printing` - Access to printer functionality
- `nativeMessaging` - Communication with Windows service
- `activeTab` - Access to current webpage
- `storage` - Save extension settings
## 🔍 Troubleshooting
### Common Issues
#### 1. Service Not Starting
**Symptoms**: API not accessible at localhost:8765
**Solutions**:
```bash
# Check service status
python -c "from service_manager import service_status; service_status()"
# Restart service manually
python service_manager.py restart
# Check Windows Event Viewer for service errors
```
#### 2. Chrome Extension Not Working
**Symptoms**: Extension shows "Service Status: Disconnected ❌"
**Solutions**:
- Verify Windows service is running
- Check firewall settings (port 8765 must be open)
- Reload the Chrome extension
- Restart Chrome browser
#### 3. Firewall Blocking Connection
**Symptoms**: Service runs but web page can't connect
**Solutions**:
```bash
# Add firewall rule manually
netsh advfirewall firewall add rule name="Quality Recticel Print Service" dir=in action=allow protocol=TCP localport=8765
# Or disable Windows Firewall temporarily to test
```
#### 4. Permission Denied Errors
**Symptoms**: Installation fails with permission errors
**Solutions**:
- Ensure running as Administrator
- Check Windows UAC settings
- Verify Python installation permissions
#### 5. Print Jobs Not Processing
**Symptoms**: API accepts requests but nothing prints
**Solutions**:
- Check default printer configuration
- Verify printer drivers are installed
- Test manual printing from other applications
- Check Windows Print Spooler service
### Log Files
Check these locations for troubleshooting:
| Component | Log Location |
|-----------|--------------|
| **Windows Service** | `print_service.log` (same folder as service) |
| **Chrome Extension** | Chrome DevTools → Extensions → Background page |
| **Windows Event Log** | Event Viewer → Windows Logs → System |
### Diagnostic Commands
```bash
# Check service status
python service_manager.py status
# Test API manually
curl http://localhost:8765/health
# List available printers
curl http://localhost:8765/printers
# Check Windows service
sc query QualityRecticelPrintService
# Check listening ports
netstat -an | findstr :8765
```
## 🔄 Maintenance
### Updating the Service
1. Stop the current service:
```bash
python service_manager.py stop
```
2. Replace service files with new versions
3. Restart the service:
```bash
python service_manager.py start
```
### Uninstalling
#### Remove Chrome Extension
1. Go to `chrome://extensions/`
2. Find "Quality Recticel Print Service"
3. Click "Remove"
#### Remove Windows Service
```bash
# Run as Administrator
python service_manager.py uninstall
```
#### Remove Firewall Rule
```bash
netsh advfirewall firewall delete rule name="Quality Recticel Print Service"
```
## 📞 Support Information
### API Endpoints Reference
| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/health` | GET | Service health check |
| `/printers` | GET | List available printers |
| `/print/pdf` | POST | Print PDF from URL |
| `/print/silent` | POST | Silent print with metadata |
### Request Examples
**Silent Print Request**:
```json
POST /print/silent
{
"pdf_url": "http://localhost:5000/generate_labels_pdf/123",
"printer_name": "default",
"copies": 1,
"silent": true,
"order_id": "123",
"quantity": "10"
}
```
**Expected Response**:
```json
{
"success": true,
"message": "Print job sent successfully",
"job_id": "print_20250921_103000",
"printer": "HP LaserJet Pro",
"timestamp": "2025-09-21T10:30:00"
}
```
## 📚 Technical Details
### Service Architecture
- **Framework**: Flask (Python)
- **Service Type**: Windows Service (pywin32)
- **Communication**: HTTP REST API + Native Messaging
- **Security**: Localhost binding only (127.0.0.1:8765)
### Chrome Extension Architecture
- **Manifest Version**: 3
- **Service Worker**: Handles background print requests
- **Content Script**: Integrates with Quality Recticel web pages
- **Native Messaging**: Communicates with Windows service
### Security Considerations
- Service only accepts local connections (localhost)
- No external network access required
- Chrome extension runs in sandboxed environment
- Windows service runs with system privileges (required for printing)
---
## 📋 Quick Start Checklist
- [ ] Download `windows_print_service` folder
- [ ] Right-click `install_service.bat` → "Run as administrator"
- [ ] Install Chrome extension from `chrome_extension` folder
- [ ] Verify service at `http://localhost:8765/health`
- [ ] Test printing from Quality Recticel web application
**Installation Time**: ~5 minutes
**User Training Required**: Minimal (automatic detection and fallback)
**Maintenance**: Zero (auto-starts with Windows)
For additional support, check the log files and diagnostic commands listed above.

View File

@@ -1,69 +0,0 @@
# 🚀 Quality Recticel Print Service - Quick Setup
## 📦 What You Get
- **Silent PDF Printing** - No more manual downloads!
- **Automatic Detection** - Smart fallback when service unavailable
- **Zero Configuration** - Works out of the box
## ⚡ 2-Minute Installation
### Step 1: Install Windows Service
1. **Right-click** `install_service.bat`
2. Select **"Run as administrator"**
3. Click **"Yes"** and wait for completion
### Step 2: Install Chrome Extension
1. Open Chrome → `chrome://extensions/`
2. Enable **"Developer mode"**
3. Click **"Load unpacked"** → Select `chrome_extension` folder
### Step 3: Verify Installation
- Visit: `http://localhost:8765/health`
- Should see: `{"status": "healthy"}`
## 🎯 How It Works
| Service Status | Button Appearance | What Happens |
|---------------|-------------------|--------------|
| **Running** ✅ | 🖨️ **Print Labels (Silent)** (Green) | Direct printing |
| **Not Running** ❌ | 📄 **Generate PDF** (Blue) | PDF download |
## ⚠️ Troubleshooting
| Problem | Solution |
|---------|----------|
| **Service won't start** | Run `install_service.bat` as Administrator |
| **Chrome extension not working** | Reload extension in `chrome://extensions/` |
| **Can't connect to localhost:8765** | Check Windows Firewall (port 8765) |
| **Nothing prints** | Verify default printer is set up |
## 🔧 Management Commands
```bash
# Check service status
python service_manager.py status
# Restart service
python service_manager.py restart
# Uninstall service
python service_manager.py uninstall
```
## 📍 Important Notes
-**Auto-starts** with Windows - no manual intervention needed
- 🔒 **Local only** - service only accessible from same computer
- 🖨️ **Uses default printer** - configure your default printer in Windows
- 💾 **Don't move files** after installation - keep folder in same location
## 🆘 Quick Support
**Service API**: `http://localhost:8765`
**Health Check**: `http://localhost:8765/health`
**Printer List**: `http://localhost:8765/printers`
**Log File**: `print_service.log` (same folder as installation)
---
*Installation takes ~5 minutes • Zero maintenance required • Works with existing Quality Recticel web application*

View File

@@ -1,348 +0,0 @@
# Quality Recticel Windows Print Service
## 🏗️ Technical Architecture
Local Windows service providing REST API for silent PDF printing via Chrome extension integration.
```
┌─────────────────────────────────────────────────────────────┐
│ Quality Recticel Web App │
│ (print_module.html) │
└─────────────────────┬───────────────────────────────────────┘
│ HTTP Request
┌─────────────────────────────────────────────────────────────┐
│ Windows Print Service │
│ (localhost:8765) │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ Flask │ │ CORS │ │ PDF Handler │ │
│ │ Server │ │ Support │ │ │ │
│ └─────────────┘ └──────────────┘ └─────────────────┘ │
└─────────────────────┬───────────────────────────────────────┘
│ Native Messaging
┌─────────────────────────────────────────────────────────────┐
│ Chrome Extension │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ Background │ │ Content │ │ Popup │ │
│ │ Service │ │ Script │ │ UI │ │
│ │ Worker │ │ │ │ │ │
│ └─────────────┘ └──────────────┘ └─────────────────┘ │
└─────────────────────┬───────────────────────────────────────┘
│ Windows API
┌─────────────────────────────────────────────────────────────┐
│ Windows Print System │
└─────────────────────────────────────────────────────────────┘
```
## 📁 Project Structure
```
windows_print_service/
├── 📄 print_service.py # Main Flask service
├── 📄 service_manager.py # Windows service wrapper
├── 📄 install_service.bat # Installation script
├── 📄 INSTALLATION_GUIDE.md # Complete documentation
├── 📄 QUICK_SETUP.md # User quick reference
├── 📄 README.md # This file
└── 📁 chrome_extension/ # Chrome extension
├── 📄 manifest.json # Extension manifest v3
├── 📄 background.js # Service worker
├── 📄 content.js # Page content integration
├── 📄 popup.html # Extension popup UI
├── 📄 popup.js # Popup functionality
└── 📁 icons/ # Extension icons
```
## 🚀 API Endpoints
### Base URL: `http://localhost:8765`
| Endpoint | Method | Description | Request Body | Response |
|----------|--------|-------------|--------------|----------|
| `/health` | GET | Service health check | None | `{"status": "healthy", ...}` |
| `/printers` | GET | List available printers | None | `{"printers": [...]}` |
| `/print/pdf` | POST | Print PDF from URL | `{"url": "...", "printer": "..."}` | `{"success": true, ...}` |
| `/print/silent` | POST | Silent print with metadata | `{"pdf_url": "...", "order_id": "..."}` | `{"success": true, ...}` |
### Example API Usage
```javascript
// Health Check
const health = await fetch('http://localhost:8765/health');
const status = await health.json();
// Silent Print
const printRequest = {
pdf_url: 'http://localhost:5000/generate_labels_pdf/123',
printer_name: 'default',
copies: 1,
silent: true,
order_id: '123',
quantity: '10'
};
const response = await fetch('http://localhost:8765/print/silent', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(printRequest)
});
```
## 🔧 Development Setup
### Prerequisites
- Python 3.8+
- Windows 10/11
- Chrome Browser
- Administrator privileges
### Local Development
```bash
# Clone/download the project
cd windows_print_service
# Install dependencies
pip install flask flask-cors requests pywin32
# Run development server (not as service)
python print_service.py
# Install as Windows service
python service_manager.py install
# Service management
python service_manager.py start
python service_manager.py stop
python service_manager.py restart
python service_manager.py uninstall
```
### Chrome Extension Development
```bash
# Load extension in Chrome
chrome://extensions/ → Developer mode ON → Load unpacked
# Debug extension
chrome://extensions/ → Details → Background page (for service worker)
chrome://extensions/ → Details → Inspect views (for popup)
```
## 📋 Configuration
### Service Configuration (`print_service.py`)
```python
class WindowsPrintService:
def __init__(self, host='127.0.0.1', port=8765):
self.host = host # Localhost binding only
self.port = port # Service port
self.app = Flask(__name__)
```
### Chrome Extension Permissions (`manifest.json`)
```json
{
"permissions": [
"printing", // Access to printer API
"nativeMessaging", // Communication with Windows service
"activeTab", // Current tab access
"storage" // Extension settings storage
]
}
```
## 🔄 Integration Flow
### 1. Service Detection
```javascript
// Web page detects service availability
const isServiceAvailable = await checkServiceHealth();
updatePrintButton(isServiceAvailable);
```
### 2. Print Request Flow
```
User clicks print → Web app → Windows service → Chrome extension → Printer
```
### 3. Fallback Mechanism
```
Service unavailable → Fallback to PDF download → Manual printing
```
## 🛠️ Customization
### Adding New Print Options
```python
# In print_service.py
@app.route('/print/custom', methods=['POST'])
def print_custom():
data = request.json
# Custom print logic here
return jsonify({'success': True})
```
### Modifying Chrome Extension
```javascript
// In background.js - Add new message handler
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'CUSTOM_PRINT') {
// Custom print logic
}
});
```
### Web Application Integration
```javascript
// In print_module.html - Modify print function
async function customPrintFunction(orderId) {
const response = await fetch('http://localhost:8765/print/custom', {
method: 'POST',
body: JSON.stringify({orderId, customOptions: {...}})
});
}
```
## 🧪 Testing
### Unit Tests (Future Enhancement)
```python
# test_print_service.py
import unittest
from print_service import WindowsPrintService
class TestPrintService(unittest.TestCase):
def test_health_endpoint(self):
# Test implementation
pass
```
### Manual Testing Checklist
- [ ] Service starts automatically on Windows boot
- [ ] API endpoints respond correctly
- [ ] Chrome extension loads without errors
- [ ] Print jobs execute successfully
- [ ] Fallback works when service unavailable
- [ ] Firewall allows port 8765 traffic
## 📊 Monitoring & Logging
### Log Files
- **Service Log**: `print_service.log` (Flask application logs)
- **Windows Event Log**: Windows Services logs
- **Chrome DevTools**: Extension console logs
### Health Monitoring
```python
# Monitor service health
import requests
try:
response = requests.get('http://localhost:8765/health', timeout=5)
if response.status_code == 200:
print("✅ Service healthy")
except:
print("❌ Service unavailable")
```
## 🔒 Security Considerations
### Network Security
- **Localhost Only**: Service binds to 127.0.0.1 (no external access)
- **No Authentication**: Relies on local machine security
- **Firewall Rule**: Port 8765 opened for local connections only
### Chrome Extension Security
- **Manifest V3**: Latest security standards
- **Minimal Permissions**: Only necessary permissions requested
- **Sandboxed**: Runs in Chrome's security sandbox
### Windows Service Security
- **System Service**: Runs with appropriate Windows service privileges
- **Print Permissions**: Requires printer access (normal for print services)
## 🚀 Deployment
### Production Deployment
1. **Package Distribution**:
```bash
# Create deployment package
zip -r quality_recticel_print_service.zip windows_print_service/
```
2. **Installation Script**: Use `install_service.bat` for end users
3. **Group Policy Deployment**: Deploy Chrome extension via enterprise policies
### Enterprise Considerations
- **Silent Installation**: Modify `install_service.bat` for unattended install
- **Registry Deployment**: Pre-configure Chrome extension registry entries
- **Network Policies**: Ensure firewall policies allow localhost:8765
## 📚 Dependencies
### Python Packages
```
flask>=2.3.0 # Web framework
flask-cors>=4.0.0 # CORS support
requests>=2.31.0 # HTTP client
pywin32>=306 # Windows service integration
```
### Chrome APIs
- `chrome.printing.*` - Printing functionality
- `chrome.runtime.*` - Extension messaging
- `chrome.nativeMessaging.*` - Native app communication
## 🐛 Debugging
### Common Debug Commands
```bash
# Check service status
sc query QualityRecticelPrintService
# Test API manually
curl http://localhost:8765/health
# Check listening ports
netstat -an | findstr :8765
# View service logs
type print_service.log
```
### Chrome Extension Debugging
```javascript
// In background.js - Add debug logging
console.log('Print request received:', message);
// In popup.js - Test API connection
fetch('http://localhost:8765/health')
.then(r => r.json())
.then(data => console.log('Service status:', data));
```
---
## 📄 License & Support
**Project**: Quality Recticel Print Service
**Version**: 1.0
**Compatibility**: Windows 10/11, Chrome 88+
**Maintenance**: Zero-maintenance after installation
For technical support, refer to `INSTALLATION_GUIDE.md` troubleshooting section.

View File

@@ -0,0 +1,539 @@
// 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');
});

View File

@@ -1,35 +0,0 @@
QZ TRAY LIBRARY PATCH NOTES
===========================
Version: 2.2.4 (patched for custom QZ Tray with pairing key authentication)
Date: October 2, 2025
CHANGES MADE:
-------------
1. Line ~387: Commented out certificate sending
- Original: _qz.websocket.connection.sendData({ certificate: cert, promise: openPromise });
- Patched: openPromise.resolve(); (resolves immediately without sending certificate)
2. Line ~391-403: Bypassed certificate retrieval
- Original: Called _qz.security.callCert() to get certificate from user
- Patched: Directly calls sendCert(null) without trying to get certificate
3. Comments added to indicate patches
REASON FOR PATCHES:
------------------
The custom QZ Tray server has certificate validation COMPLETELY DISABLED.
It uses ONLY pairing key (HMAC) authentication instead of certificates.
The original qz-tray.js library expects certificate-based authentication and
fails when the server doesn't respond to certificate requests.
COMPATIBILITY:
-------------
- Works with custom QZ Tray server (forked version with certificate validation disabled)
- NOT compatible with standard QZ Tray servers
- Connects to both ws://localhost:8181 and wss://localhost:8182
- Authentication handled by server-side pairing keys
BACKUP:
-------
Original unpatched version saved as: qz-tray.js.backup