"""Printedparts plugin API routes. Reads are open (jwt optional) like every list surface; mutations arrive in later stages with permission gates. The kiosk endpoints (unauthenticated by explicit decision - see the proposal) also land later. """ from flask import Blueprint, request from flask_jwt_extended import jwt_required from sqlalchemy import or_ from shopdb.api import ( db, success_response, error_response, paginated_response, ErrorCodes, get_pagination_params, paginate_query, ) from ..models import PrintedItem printedparts_bp = Blueprint('printedparts', __name__) @printedparts_bp.route('/items', methods=['GET']) @jwt_required(optional=True) def list_items(): """List printed items, paginated; search + low-stock filter.""" page, per_page = get_pagination_params(request) query = PrintedItem.query if request.args.get('active', 'true').lower() != 'false': query = query.filter(PrintedItem.isactive == True) if search := request.args.get('search'): like = f'%{search}%' query = query.filter(or_( PrintedItem.itemcode.ilike(like), PrintedItem.itemname.ilike(like), PrintedItem.itemdescription.ilike(like), PrintedItem.binlocation.ilike(like), )) if request.args.get('lowstock', '').lower() == 'true': query = query.filter( PrintedItem.quantityonhand <= PrintedItem.lowstockthreshold) query = query.order_by(PrintedItem.itemname) items, total = paginate_query(query, page, per_page) return paginated_response( [item.to_dict() for item in items], page, per_page, total) @printedparts_bp.route('/items/', methods=['GET']) @jwt_required(optional=True) def get_item(item_id: int): """Get one printed item with its recent transactions.""" item = db.session.get(PrintedItem, item_id) if not item: return error_response(ErrorCodes.NOT_FOUND, f'Printed item {item_id} not found', http_code=404) data = item.to_dict() recent = (item.transactions .order_by(db.desc('transactiondate')) .limit(25).all()) data['recenttransactions'] = [t.to_dict() for t in recent] return success_response(data)