diff --git a/app.py b/app.py index fa18fa6..be47068 100644 --- a/app.py +++ b/app.py @@ -16,11 +16,14 @@ from db import query_db, execute_db, get_db from blueprints.data_imports import data_imports_bp from blueprints.users import users_bp from blueprints.sessions import sessions_bp -from utils import login_required, role_required +from blueprints.admin_locations import admin_locations_bp +from utils import login_required +# Register Blueprints app.register_blueprint(data_imports_bp) app.register_blueprint(users_bp) app.register_blueprint(sessions_bp) +app.register_blueprint(admin_locations_bp) # V1.0: Use environment variable for production, fallback to demo key for development app.secret_key = os.environ.get('SCANLOOK_SECRET_KEY', 'scanlook-demo-key-replace-for-production') @@ -241,91 +244,6 @@ def complete_location(location_count_id): return jsonify({'success': True, 'message': 'Bin marked as complete'}) -@app.route('/location//reopen', methods=['POST']) -@login_required -def reopen_location(location_count_id): - """Reopen a completed location (admin/owner only)""" - # Check permissions - user = query_db('SELECT role FROM Users WHERE user_id = ?', [session['user_id']], one=True) - if not user or user['role'] not in ['owner', 'admin']: - return jsonify({'success': False, 'message': 'Permission denied'}), 403 - - # Verify location exists - loc = query_db('SELECT * FROM LocationCounts WHERE location_count_id = ?', [location_count_id], one=True) - - if not loc: - return jsonify({'success': False, 'message': 'Location not found'}) - - # Reopen the location - execute_db(''' - UPDATE LocationCounts - SET status = 'in_progress', end_timestamp = NULL - WHERE location_count_id = ? - ''', [location_count_id]) - - return jsonify({'success': True, 'message': 'Bin reopened for counting'}) - - -@app.route('/location//delete', methods=['POST']) -@login_required -def delete_location_count(location_count_id): - """Delete all counts for a location (soft delete)""" - # Verify ownership - loc = query_db('SELECT * FROM LocationCounts WHERE location_count_id = ?', [location_count_id], one=True) - - if not loc: - return jsonify({'success': False, 'message': 'Location not found'}) - - if loc['counted_by'] != session['user_id'] and session['role'] not in ['owner', 'admin']: - return jsonify({'success': False, 'message': 'Permission denied'}) - - # Soft delete all scan entries for this location - execute_db(''' - UPDATE ScanEntries - SET is_deleted = 1 - WHERE location_count_id = ? - ''', [location_count_id]) - - # Delete the location count record - execute_db(''' - DELETE FROM LocationCounts - WHERE location_count_id = ? - ''', [location_count_id]) - - return jsonify({'success': True, 'message': 'Bin count deleted'}) - - -@app.route('/location//scans') -@login_required -def get_location_scans(location_count_id): - """Get all scans for a specific location (admin/owner only)""" - # Check permissions - user = query_db('SELECT role FROM Users WHERE user_id = ?', [session['user_id']], one=True) - if not user or user['role'] not in ['owner', 'admin']: - return jsonify({'success': False, 'message': 'Permission denied'}), 403 - - try: - scans = query_db(''' - SELECT - se.*, - bic.system_bin as current_system_location, - bic.system_quantity as current_system_weight - FROM ScanEntries se - LEFT JOIN BaselineInventory_Current bic ON se.lot_number = bic.lot_number - WHERE se.location_count_id = ? - AND se.is_deleted = 0 - ORDER BY se.scan_timestamp DESC - ''', [location_count_id]) - - # Convert Row objects to dicts - scans_list = [dict(scan) for scan in scans] if scans else [] - - return jsonify({'success': True, 'scans': scans_list}) - - except Exception as e: - return jsonify({'success': False, 'message': str(e)}) - - @app.route('/count//location/') @login_required def count_location(session_id, location_count_id): diff --git a/blueprints/__pycache__/admin_locations.cpython-313.pyc b/blueprints/__pycache__/admin_locations.cpython-313.pyc new file mode 100644 index 0000000..3738e32 Binary files /dev/null and b/blueprints/__pycache__/admin_locations.cpython-313.pyc differ diff --git a/blueprints/admin_locations.py b/blueprints/admin_locations.py new file mode 100644 index 0000000..5a96514 --- /dev/null +++ b/blueprints/admin_locations.py @@ -0,0 +1,89 @@ +from flask import Blueprint, jsonify, session +from db import query_db, execute_db +from utils import login_required + +admin_locations_bp = Blueprint('admin_locations', __name__) + +@admin_locations_bp.route('/location//reopen', methods=['POST']) +@login_required +def reopen_location(location_count_id): + """Reopen a completed location (admin/owner only)""" + # Check permissions + user = query_db('SELECT role FROM Users WHERE user_id = ?', [session['user_id']], one=True) + if not user or user['role'] not in ['owner', 'admin']: + return jsonify({'success': False, 'message': 'Permission denied'}), 403 + + # Verify location exists + loc = query_db('SELECT * FROM LocationCounts WHERE location_count_id = ?', [location_count_id], one=True) + + if not loc: + return jsonify({'success': False, 'message': 'Location not found'}) + + # Reopen the location + execute_db(''' + UPDATE LocationCounts + SET status = 'in_progress', end_timestamp = NULL + WHERE location_count_id = ? + ''', [location_count_id]) + + return jsonify({'success': True, 'message': 'Bin reopened for counting'}) + + +@admin_locations_bp.route('/location//delete', methods=['POST']) +@login_required +def delete_location_count(location_count_id): + """Delete all counts for a location (soft delete)""" + # Verify ownership + loc = query_db('SELECT * FROM LocationCounts WHERE location_count_id = ?', [location_count_id], one=True) + + if not loc: + return jsonify({'success': False, 'message': 'Location not found'}) + + if loc['counted_by'] != session['user_id'] and session['role'] not in ['owner', 'admin']: + return jsonify({'success': False, 'message': 'Permission denied'}) + + # Soft delete all scan entries for this location + execute_db(''' + UPDATE ScanEntries + SET is_deleted = 1 + WHERE location_count_id = ? + ''', [location_count_id]) + + # Delete the location count record + execute_db(''' + DELETE FROM LocationCounts + WHERE location_count_id = ? + ''', [location_count_id]) + + return jsonify({'success': True, 'message': 'Bin count deleted'}) + + +@admin_locations_bp.route('/location//scans') +@login_required +def get_location_scans(location_count_id): + """Get all scans for a specific location (admin/owner only)""" + # Check permissions + user = query_db('SELECT role FROM Users WHERE user_id = ?', [session['user_id']], one=True) + if not user or user['role'] not in ['owner', 'admin']: + return jsonify({'success': False, 'message': 'Permission denied'}), 403 + + try: + scans = query_db(''' + SELECT + se.*, + bic.system_bin as current_system_location, + bic.system_quantity as current_system_weight + FROM ScanEntries se + LEFT JOIN BaselineInventory_Current bic ON se.lot_number = bic.lot_number + WHERE se.location_count_id = ? + AND se.is_deleted = 0 + ORDER BY se.scan_timestamp DESC + ''', [location_count_id]) + + # Convert Row objects to dicts + scans_list = [dict(scan) for scan in scans] if scans else [] + + return jsonify({'success': True, 'scans': scans_list}) + + except Exception as e: + return jsonify({'success': False, 'message': str(e)}) \ No newline at end of file diff --git a/database/scanlook.db b/database/scanlook.db index 5795be9..72e0bcb 100644 Binary files a/database/scanlook.db and b/database/scanlook.db differ