"""Models (equipment models) 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 Model from shopdb.utils.responses import ( success_response, error_response, paginated_response, ErrorCodes ) from shopdb.utils.pagination import get_pagination_params, paginate_query models_bp = Blueprint('models', __name__) @models_bp.route('', methods=['GET']) @jwt_required(optional=True) def list_models(): """List all equipment models.""" page, per_page = get_pagination_params(request) query = Model.query if request.args.get('active', 'true').lower() != 'false': query = query.filter(Model.isactive == True) if vendor_id := request.args.get('vendor', type=int): query = query.filter(Model.vendorid == vendor_id) if machinetype_id := request.args.get('machinetype', type=int): query = query.filter(Model.machinetypeid == machinetype_id) if search := request.args.get('search'): query = query.filter(Model.modelnumber.ilike(f'%{search}%')) query = query.order_by(Model.modelnumber) items, total = paginate_query(query, page, per_page) data = [] for m in items: d = m.to_dict() d['vendor'] = m.vendor.vendor if m.vendor else None d['machinetype'] = m.machinetype.machinetype if m.machinetype else None data.append(d) return paginated_response(data, page, per_page, total) @models_bp.route('/', methods=['GET']) @jwt_required(optional=True) def get_model(model_id: int): """Get a single model.""" m = Model.query.get(model_id) if not m: return error_response( ErrorCodes.NOT_FOUND, f'Model with ID {model_id} not found', http_code=404 ) data = m.to_dict() data['vendor'] = m.vendor.to_dict() if m.vendor else None data['machinetype'] = m.machinetype.to_dict() if m.machinetype else None return success_response(data) @models_bp.route('', methods=['POST']) @jwt_required() def create_model(): """Create a new model.""" data = request.get_json() if not data or not data.get('modelnumber'): return error_response(ErrorCodes.VALIDATION_ERROR, 'modelnumber is required') # Check duplicate existing = Model.query.filter_by( modelnumber=data['modelnumber'], vendorid=data.get('vendorid') ).first() if existing: return error_response( ErrorCodes.CONFLICT, f"Model '{data['modelnumber']}' already exists for this vendor", http_code=409 ) m = Model( modelnumber=data['modelnumber'], vendorid=data.get('vendorid'), machinetypeid=data.get('machinetypeid'), description=data.get('description'), imageurl=data.get('imageurl'), documentationurl=data.get('documentationurl'), notes=data.get('notes') ) db.session.add(m) db.session.commit() return success_response(m.to_dict(), message='Model created', http_code=201) @models_bp.route('/', methods=['PUT']) @jwt_required() def update_model(model_id: int): """Update a model.""" m = Model.query.get(model_id) if not m: return error_response( ErrorCodes.NOT_FOUND, f'Model with ID {model_id} not found', http_code=404 ) data = request.get_json() if not data: return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided') for key in ['modelnumber', 'vendorid', 'machinetypeid', 'description', 'imageurl', 'documentationurl', 'notes', 'isactive']: if key in data: setattr(m, key, data[key]) db.session.commit() return success_response(m.to_dict(), message='Model updated') @models_bp.route('/', methods=['DELETE']) @jwt_required() def delete_model(model_id: int): """Delete (deactivate) a model.""" m = Model.query.get(model_id) if not m: return error_response( ErrorCodes.NOT_FOUND, f'Model with ID {model_id} not found', http_code=404 ) m.isactive = False db.session.commit() return success_response(message='Model deleted')