Spaces:
Runtime error
Runtime error
| from flask import jsonify, request, current_app | |
| from flask_jwt_extended import jwt_required, get_jwt_identity | |
| from app.models.material import Material | |
| from app.api import bp, ns_materials, api | |
| from app import db | |
| from app.utils.validators import validate_json, validate_decimal | |
| from flask_restx import Resource, fields | |
| from sqlalchemy import distinct | |
| # API 模型定义 | |
| material_model = api.model('Material', { | |
| 'name': fields.String(required=True, description='Material name'), | |
| 'unit': fields.String(required=True, description='Unit of measurement'), | |
| 'category': fields.String(required=False, description='Material category'), | |
| 'warning_threshold': fields.Float(required=True, description='Warning threshold quantity'), | |
| 'processed_name': fields.String(required=False, description='Processed material name'), | |
| 'processed_unit': fields.String(required=False, description='Processed material unit'), | |
| 'processed_warning_threshold': fields.Float(required=False, description='Processed material warning threshold'), | |
| 'conversion_ratio': fields.Float(required=False, description='Conversion ratio from raw to processed material') | |
| }) | |
| class MaterialCategoriesResource(Resource): | |
| def get(self): | |
| """获取所有物料分类列表""" | |
| try: | |
| # 从数据库中查询所有不同的分类 | |
| categories_query = db.session.query(distinct(Material.category)).all() | |
| # 提取分类名称,排除空值和None | |
| db_categories = [category[0] for category in categories_query if category[0]] | |
| # 排序 | |
| db_categories.sort() # 按字母顺序排序 | |
| # 注释掉强制添加"其他"分类的代码,只显示数据库中存在的分类 | |
| # if '其他' not in db_categories: | |
| # db_categories.append('其他') | |
| # else: | |
| # # 如果"其他"分类已存在,将其移到最后 | |
| # db_categories.remove('其他') | |
| # db_categories.append('其他') | |
| current_app.logger.debug(f"Found {len(db_categories)} material categories") | |
| return {'data': db_categories} | |
| except Exception as e: | |
| current_app.logger.error(f'Error fetching material categories: {str(e)}') | |
| return {'message': 'Error fetching material categories'}, 500 | |
| class MaterialResource(Resource): | |
| def get(self): | |
| """获取所有物料列表""" | |
| try: | |
| materials = Material.query.all() | |
| result = [{ | |
| 'id': m.id, | |
| 'name': m.name, | |
| 'unit': m.unit, | |
| 'category': m.category, | |
| 'warning_threshold': float(m.warning_threshold), | |
| 'processed_name': m.processed_name, | |
| 'processed_unit': m.processed_unit, | |
| 'processed_warning_threshold': float(m.processed_warning_threshold) if m.processed_warning_threshold else None, | |
| 'conversion_ratio': float(m.conversion_ratio) if m.conversion_ratio else None, | |
| 'created_at': m.created_at.isoformat() | |
| } for m in materials] | |
| # 打印调试信息 | |
| current_app.logger.debug(f"Found {len(result)} materials") | |
| return {'data': result} | |
| except Exception as e: | |
| current_app.logger.error(f'Error fetching materials: {str(e)}') | |
| return {'message': 'Error fetching materials'}, 500 | |
| def post(self): | |
| """创建新物料""" | |
| try: | |
| data = request.get_json() | |
| # 验证数据 | |
| warning_threshold = validate_decimal(data['warning_threshold']) | |
| if warning_threshold is None or warning_threshold <= 0: | |
| return {'message': 'Invalid warning threshold value'}, 400 | |
| # 检查名称是否已存在 | |
| if Material.query.filter_by(name=data['name']).first(): | |
| return {'message': 'Material name already exists'}, 400 | |
| # 处理加工物料相关数据 | |
| processed_warning_threshold = None | |
| if 'processed_warning_threshold' in data and data['processed_warning_threshold']: | |
| processed_warning_threshold = validate_decimal(data['processed_warning_threshold']) | |
| if processed_warning_threshold is not None and processed_warning_threshold <= 0: | |
| return {'message': 'Invalid processed warning threshold value'}, 400 | |
| conversion_ratio = None | |
| if 'conversion_ratio' in data and data['conversion_ratio']: | |
| conversion_ratio = validate_decimal(data['conversion_ratio']) | |
| if conversion_ratio is not None and conversion_ratio <= 0: | |
| return {'message': 'Invalid conversion ratio value'}, 400 | |
| material = Material( | |
| name=data['name'], | |
| unit=data['unit'], | |
| category=data.get('category', '其他'), | |
| warning_threshold=warning_threshold, | |
| processed_name=data.get('processed_name'), | |
| processed_unit=data.get('processed_unit'), | |
| processed_warning_threshold=processed_warning_threshold, | |
| conversion_ratio=conversion_ratio | |
| ) | |
| db.session.add(material) | |
| db.session.commit() | |
| return jsonify({ | |
| 'id': material.id, | |
| 'name': material.name, | |
| 'unit': material.unit, | |
| 'category': material.category, | |
| 'warning_threshold': float(material.warning_threshold), | |
| 'processed_name': material.processed_name, | |
| 'processed_unit': material.processed_unit, | |
| 'processed_warning_threshold': float(material.processed_warning_threshold) if material.processed_warning_threshold else None, | |
| 'conversion_ratio': float(material.conversion_ratio) if material.conversion_ratio else None, | |
| 'created_at': material.created_at.isoformat() | |
| }) | |
| except Exception as e: | |
| current_app.logger.error(f'Error creating material: {str(e)}') | |
| db.session.rollback() | |
| return {'message': 'Error creating material'}, 500 | |
| class MaterialDetail(Resource): | |
| def put(self, id): | |
| """更新物料信息""" | |
| try: | |
| material = Material.query.get_or_404(id) | |
| data = request.get_json() | |
| if 'name' in data and data['name'] != material.name: | |
| if Material.query.filter_by(name=data['name']).first(): | |
| return {'message': 'Material name already exists'}, 400 | |
| material.name = data['name'] | |
| if 'unit' in data: | |
| material.unit = data['unit'] | |
| if 'category' in data: | |
| material.category = data['category'] | |
| if 'warning_threshold' in data: | |
| warning_threshold = validate_decimal(data['warning_threshold']) | |
| if warning_threshold is None or warning_threshold <= 0: | |
| return {'message': 'Invalid warning threshold value'}, 400 | |
| material.warning_threshold = warning_threshold | |
| # 更新物料加工相关字段 | |
| if 'processed_name' in data: | |
| material.processed_name = data['processed_name'] | |
| if 'processed_unit' in data: | |
| material.processed_unit = data['processed_unit'] | |
| if 'processed_warning_threshold' in data: | |
| if data['processed_warning_threshold']: | |
| processed_warning_threshold = validate_decimal(data['processed_warning_threshold']) | |
| if processed_warning_threshold is not None and processed_warning_threshold <= 0: | |
| return {'message': 'Invalid processed warning threshold value'}, 400 | |
| material.processed_warning_threshold = processed_warning_threshold | |
| else: | |
| material.processed_warning_threshold = None | |
| if 'conversion_ratio' in data: | |
| if data['conversion_ratio']: | |
| conversion_ratio = validate_decimal(data['conversion_ratio']) | |
| if conversion_ratio is not None and conversion_ratio <= 0: | |
| return {'message': 'Invalid conversion ratio value'}, 400 | |
| material.conversion_ratio = conversion_ratio | |
| else: | |
| material.conversion_ratio = None | |
| db.session.commit() | |
| return jsonify({ | |
| 'id': material.id, | |
| 'name': material.name, | |
| 'unit': material.unit, | |
| 'category': material.category, | |
| 'warning_threshold': float(material.warning_threshold), | |
| 'processed_name': material.processed_name, | |
| 'processed_unit': material.processed_unit, | |
| 'processed_warning_threshold': float(material.processed_warning_threshold) if material.processed_warning_threshold else None, | |
| 'conversion_ratio': float(material.conversion_ratio) if material.conversion_ratio else None, | |
| 'created_at': material.created_at.isoformat() | |
| }) | |
| except Exception as e: | |
| current_app.logger.error(f'Error updating material: {str(e)}') | |
| db.session.rollback() | |
| return {'message': 'Error updating material'}, 500 | |
| def delete(self, id): | |
| """删除物料""" | |
| try: | |
| material = Material.query.get_or_404(id) | |
| # 检查是否有关联的库存记录,但不阻止删除 | |
| has_inventory = len(material.inventories) > 0 | |
| if has_inventory: | |
| # 如果有库存记录,先删除所有相关的库存记录 | |
| for inventory in material.inventories: | |
| db.session.delete(inventory) | |
| # 删除物料 | |
| db.session.delete(material) | |
| db.session.commit() | |
| return '', 204 | |
| except Exception as e: | |
| current_app.logger.error(f'Error deleting material: {str(e)}') | |
| db.session.rollback() | |
| return {'message': 'Error deleting material'}, 500 |