"""Locations API endpoints - Full CRUD.""" from flask import Blueprint, request from flask_jwt_extended import jwt_required from shopdb.extensions import db from shopdb.core.models import Location from shopdb.utils.responses import ( success_response, error_response, paginated_response, ErrorCodes ) from shopdb.utils.pagination import get_pagination_params, paginate_query locations_bp = Blueprint('locations', __name__) @locations_bp.route('', methods=['GET']) @jwt_required(optional=True) def list_locations(): """List all locations.""" page, per_page = get_pagination_params(request) query = Location.query if request.args.get('active', 'true').lower() != 'false': query = query.filter(Location.isactive == True) if search := request.args.get('search'): query = query.filter( db.or_( Location.locationname.ilike(f'%{search}%'), Location.building.ilike(f'%{search}%') ) ) query = query.order_by(Location.locationname) items, total = paginate_query(query, page, per_page) data = [loc.to_dict() for loc in items] return paginated_response(data, page, per_page, total) @locations_bp.route('/', methods=['GET']) @jwt_required(optional=True) def get_location(location_id: int): """Get a single location.""" loc = Location.query.get(location_id) if not loc: return error_response( ErrorCodes.NOT_FOUND, f'Location with ID {location_id} not found', http_code=404 ) return success_response(loc.to_dict()) @locations_bp.route('', methods=['POST']) @jwt_required() def create_location(): """Create a new location.""" data = request.get_json() if not data or not data.get('locationname'): return error_response(ErrorCodes.VALIDATION_ERROR, 'locationname is required') if Location.query.filter_by(locationname=data['locationname']).first(): return error_response( ErrorCodes.CONFLICT, f"Location '{data['locationname']}' already exists", http_code=409 ) loc = Location( locationname=data['locationname'], building=data.get('building'), floor=data.get('floor'), room=data.get('room'), description=data.get('description'), mapimage=data.get('mapimage'), mapwidth=data.get('mapwidth'), mapheight=data.get('mapheight') ) db.session.add(loc) db.session.commit() return success_response(loc.to_dict(), message='Location created', http_code=201) @locations_bp.route('/', methods=['PUT']) @jwt_required() def update_location(location_id: int): """Update a location.""" loc = Location.query.get(location_id) if not loc: return error_response( ErrorCodes.NOT_FOUND, f'Location with ID {location_id} not found', http_code=404 ) data = request.get_json() if not data: return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided') if 'locationname' in data and data['locationname'] != loc.locationname: if Location.query.filter_by(locationname=data['locationname']).first(): return error_response( ErrorCodes.CONFLICT, f"Location '{data['locationname']}' already exists", http_code=409 ) for key in ['locationname', 'building', 'floor', 'room', 'description', 'mapimage', 'mapwidth', 'mapheight', 'isactive']: if key in data: setattr(loc, key, data[key]) db.session.commit() return success_response(loc.to_dict(), message='Location updated') @locations_bp.route('/', methods=['DELETE']) @jwt_required() def delete_location(location_id: int): """Delete (deactivate) a location.""" loc = Location.query.get(location_id) if not loc: return error_response( ErrorCodes.NOT_FOUND, f'Location with ID {location_id} not found', http_code=404 ) loc.isactive = False db.session.commit() return success_response(message='Location deleted')