Files
quality_app-v2/documentation/DATABASE_TRIGGERS_IMPLEMENTATION.md
Quality App Developer 07f77603eb Implement approved/rejected quantity triggers and warehouse inventory
Database Triggers Implementation:
- Added automatic quantity calculation triggers for scanfg_orders
- Added automatic quantity calculation triggers for scan1_orders (T1 phase)
- Triggers calculate based on CP_base_code grouping (8 digits)
- Quality code: 0 = approved, != 0 = rejected
- Quantities set at insertion time (BEFORE INSERT trigger)
- Added create_triggers() function to initialize_db.py

Warehouse Inventory Enhancement:
- Analyzed old app database quantity calculation logic
- Created comprehensive trigger implementation guide
- Added trigger verification and testing procedures
- Documented data migration strategy

Documentation Added:
- APPROVED_REJECTED_QUANTITIES_ANALYSIS.md - Old app logic analysis
- DATABASE_TRIGGERS_IMPLEMENTATION.md - v2 implementation guide
- WAREHOUSE_INVENTORY_IMPLEMENTATION.md - Inventory view feature

Files Modified:
- initialize_db.py: Added create_triggers() function and call in main()
- Documentation: 3 comprehensive guides for database and inventory management

Quality Metrics:
- Triggers maintain legacy compatibility
- Automatic calculation ensures data consistency
- Performance optimized at database level
- Comprehensive testing documented
2026-01-30 12:30:56 +02:00

355 lines
11 KiB
Markdown

# 🔄 Database Triggers Implementation for v2
**Date:** January 30, 2026
**Status:** ✅ Ready for Implementation
**Priority:** HIGH
---
## 📋 SQL Triggers for v2 scanfg_orders
### Current Situation
The v2 application has the scanfg_orders table but:
- ❌ No database triggers for automatic calculation
- ❌ CP_base_code not extracted automatically
- ❌ Quantities may be entered manually or not calculated
### Required Implementation
#### 1. Add Generated Column (if not present)
```sql
-- Check if cp_base_code column exists
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'scanfg_orders' AND COLUMN_NAME = 'cp_base_code';
-- If not exists, add it:
ALTER TABLE scanfg_orders
ADD COLUMN cp_base_code VARCHAR(10)
GENERATED ALWAYS AS (SUBSTRING(CP_full_code, 1, 10)) STORED;
-- Add index for performance
CREATE INDEX idx_cp_base_code ON scanfg_orders(cp_base_code);
```
#### 2. Create Trigger for Automatic Quantity Calculation
```sql
-- Drop existing trigger if present
DROP TRIGGER IF EXISTS set_quantities_fg;
-- Create new trigger
CREATE TRIGGER set_quantities_fg
BEFORE INSERT ON scanfg_orders
FOR EACH ROW
BEGIN
-- Count how many APPROVED entries exist for this CP_base_code
SET @approved = (
SELECT COUNT(*) FROM scanfg_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code = 0
);
-- Count how many REJECTED entries exist for this CP_base_code
SET @rejected = (
SELECT COUNT(*) FROM scanfg_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code != 0
);
-- Set quantities based on this new row's quality_code
IF NEW.quality_code = 0 THEN
-- Approved scan: increment approved count
SET NEW.approved_quantity = @approved + 1;
SET NEW.rejected_quantity = @rejected;
ELSE
-- Rejected scan: increment rejected count
SET NEW.approved_quantity = @approved;
SET NEW.rejected_quantity = @rejected + 1;
END IF;
END;
```
#### 3. Same for scan1_orders (T1 Phase)
```sql
DROP TRIGGER IF EXISTS set_quantities_scan1;
CREATE TRIGGER set_quantities_scan1
BEFORE INSERT ON scan1_orders
FOR EACH ROW
BEGIN
SET @approved = (
SELECT COUNT(*) FROM scan1_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code = 0
);
SET @rejected = (
SELECT COUNT(*) FROM scan1_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code != 0
);
IF NEW.quality_code = 0 THEN
SET NEW.approved_quantity = @approved + 1;
SET NEW.rejected_quantity = @rejected;
ELSE
SET NEW.approved_quantity = @approved;
SET NEW.rejected_quantity = @rejected + 1;
END IF;
END;
```
---
## 🔍 Verification Queries
### Check if Triggers Exist
```sql
SELECT TRIGGER_NAME, TRIGGER_SCHEMA, TRIGGER_TABLE, ACTION_STATEMENT
FROM INFORMATION_SCHEMA.TRIGGERS
WHERE TRIGGER_SCHEMA = 'quality_app_v2'
AND TRIGGER_TABLE IN ('scanfg_orders', 'scan1_orders');
```
### Verify Trigger is Working
```sql
-- Insert test record
INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time)
VALUES ('OP01', 'CP00000001-0001', 'OC01', 'OC02', 0, CURDATE(), CURTIME());
-- Check if quantities were set automatically
SELECT Id, CP_full_code, quality_code, approved_quantity, rejected_quantity
FROM scanfg_orders
WHERE CP_full_code = 'CP00000001-0001';
-- Should show: approved_quantity = 1, rejected_quantity = 0
```
### Full Test Scenario
```sql
-- Step 1: Insert approved record
INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time)
VALUES ('OP01', 'CP00000001-0001', 'OC01', 'OC02', 0, CURDATE(), CURTIME());
-- Expected: approved_qty=1, rejected_qty=0
-- Step 2: Insert another approved record
INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time)
VALUES ('OP02', 'CP00000001-0002', 'OC01', 'OC02', 0, CURDATE(), CURTIME());
-- Expected: approved_qty=2, rejected_qty=0
-- Step 3: Insert rejected record
INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time)
VALUES ('OP01', 'CP00000001-0003', 'OC01', 'OC02', 2, CURDATE(), CURTIME());
-- Expected: approved_qty=2, rejected_qty=1
-- Verify all records
SELECT CP_full_code, quality_code, approved_quantity, rejected_quantity
FROM scanfg_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = 'CP00000001'
ORDER BY Id;
```
---
## 🔧 Integration Points in Python Code
### 1. Database Initialization (initialize_db.py)
Add trigger creation to the database setup:
```python
def create_scan_triggers():
"""Create triggers for automatic quantity calculation"""
try:
conn = get_db()
cursor = conn.cursor()
# Drop existing triggers
cursor.execute("DROP TRIGGER IF EXISTS set_quantities_fg")
cursor.execute("DROP TRIGGER IF EXISTS set_quantities_scan1")
# Create scanfg_orders trigger
cursor.execute("""
CREATE TRIGGER set_quantities_fg
BEFORE INSERT ON scanfg_orders
FOR EACH ROW
BEGIN
SET @approved = (SELECT COUNT(*) FROM scanfg_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code = 0);
SET @rejected = (SELECT COUNT(*) FROM scanfg_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code != 0);
IF NEW.quality_code = 0 THEN
SET NEW.approved_quantity = @approved + 1;
SET NEW.rejected_quantity = @rejected;
ELSE
SET NEW.approved_quantity = @approved;
SET NEW.rejected_quantity = @rejected + 1;
END IF;
END
""")
logger.info("✓ Trigger 'set_quantities_fg' created")
# Create scan1_orders trigger (similar)
cursor.execute("""
CREATE TRIGGER set_quantities_scan1
BEFORE INSERT ON scan1_orders
FOR EACH ROW
BEGIN
SET @approved = (SELECT COUNT(*) FROM scan1_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code = 0);
SET @rejected = (SELECT COUNT(*) FROM scan1_orders
WHERE SUBSTRING(CP_full_code, 1, 10) = SUBSTRING(NEW.CP_full_code, 1, 10)
AND quality_code != 0);
IF NEW.quality_code = 0 THEN
SET NEW.approved_quantity = @approved + 1;
SET NEW.rejected_quantity = @rejected;
ELSE
SET NEW.approved_quantity = @approved;
SET NEW.rejected_quantity = @rejected + 1;
END IF;
END
""")
logger.info("✓ Trigger 'set_quantities_scan1' created")
conn.commit()
cursor.close()
return True
except Exception as e:
logger.error(f"✗ Error creating triggers: {e}")
return False
```
### 2. FG Scan Form (fg_scan.html)
Ensure quality_code is set correctly:
```python
# In routes.py fg_scan endpoint
quality_status = request.form.get('quality_code', '0') # From form
# Map user input to quality_code
if quality_status.lower() in ['approved', '0']:
quality_code = 0 # Approved
else:
quality_code = 1 # Rejected (or 2, 3, etc.)
# Insert record (trigger will auto-calculate quantities)
cursor.execute("""
INSERT INTO scanfg_orders
(operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, box_id, location_id)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
""", (
operator_code, cp_full_code, oc1_code, oc2_code, quality_code,
date, time, box_id, location_id
))
# quantities are automatically set by trigger!
```
### 3. Warehouse Inventory Display
The quantities are now automatically available:
```sql
-- In warehouse.py get_cp_inventory_list()
SELECT
s.CP_full_code,
SUBSTRING(s.CP_full_code, 1, 10) as cp_base,
SUM(s.approved_quantity) as total_approved, -- Auto-calculated
SUM(s.rejected_quantity) as total_rejected, -- Auto-calculated
...
FROM scanfg_orders s
...
```
---
## 📊 Data Migration
For existing records in the database:
```sql
-- Recalculate quantities for all existing records
UPDATE scanfg_orders s1
SET
approved_quantity = (
SELECT COUNT(*) FROM scanfg_orders s2
WHERE SUBSTRING(s2.CP_full_code, 1, 10) = SUBSTRING(s1.CP_full_code, 1, 10)
AND s2.quality_code = 0
AND s2.Id <= s1.Id -- Only count up to current record
),
rejected_quantity = (
SELECT COUNT(*) FROM scanfg_orders s2
WHERE SUBSTRING(s2.CP_full_code, 1, 10) = SUBSTRING(s1.CP_full_code, 1, 10)
AND s2.quality_code != 0
AND s2.Id <= s1.Id -- Only count up to current record
);
```
---
## ✅ Checklist
- [ ] Add cp_base_code generated column to scanfg_orders
- [ ] Add cp_base_code generated column to scan1_orders
- [ ] Create set_quantities_fg trigger
- [ ] Create set_quantities_scan1 trigger
- [ ] Test with sample inserts
- [ ] Verify trigger working correctly
- [ ] Update initialize_db.py to create triggers
- [ ] Update db_schema_verifier.py to verify triggers exist
- [ ] Test with production-like data volume
- [ ] Document for team
- [ ] Deploy to production
---
## 🚀 Execution Steps
### Step 1: Test Locally
```bash
# Connect to test database
mysql -h localhost -u root -p quality_app_v2
# Run verification query
SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS
WHERE TRIGGER_TABLE IN ('scanfg_orders', 'scan1_orders');
```
### Step 2: Add to Schema Verifier
Update `db_schema_verifier.py` to check and recreate triggers if missing
### Step 3: Update initialize_db.py
Add trigger creation to database initialization sequence
### Step 4: Deploy
- Restart application
- Verify triggers created in database
- Test with new FG scan entries
---
## 📝 Notes
- Triggers execute **BEFORE INSERT** (before record is written to DB)
- Quantities are **immutable** after insertion (set once)
- Grouping is by **CP_base_code** (8 digits), not full code
- Compatible with existing data and warehouse features
- Maintains consistency with legacy application behavior
---
**Priority:** HIGH
**Effort:** MEDIUM
**Impact:** Data Accuracy, Report Correctness